<commit_before>// Copyright 2011 Johann Duscher. 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.
//
// THIS SOFTWARE IS PROVIDED BY JOHANN DUSCHER ''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 <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.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Johann Duscher.

#ifndef NZMQT_H
#define NZMQT_H

#include <zmq.hpp>

#include <QObject>
#include <QList>
#include <QByteArray>
#include <QSocketNotifier>

namespace nzmqt
{
    typedef zmq::free_fn free_fn;
    typedef zmq::pollitem_t pollitem_t;

    typedef zmq::error_t ZMQException;

    using zmq::poll;
    using zmq::device;
    using zmq::version;

    class ZMQMessage : private zmq::message_t
    {
        friend class ZMQSocket;

        typedef zmq::message_t super;

    public:
        inline ZMQMessage() : super() {}

        inline ZMQMessage(size_t size_) : super(size_) {}

        inline ZMQMessage(void* data_, size_t size_, free_fn *ffn_, void* hint_ = 0)
            : super(data_, size_, ffn_, hint_) {}

        inline ZMQMessage(const QByteArray& b) : super(b.size()) {
            memcpy(data(), b.constData(), b.size());
        }

        using super::rebuild;

        inline void move(ZMQMessage* msg_)
        {
            super::move(static_cast<zmq::message_t*>(msg_));
        }

        inline void copy(ZMQMessage* msg_)
        {
            super::copy(msg_);
        }

        inline void clone(ZMQMessage* msg_)
        {
            rebuild(msg_->size());
            memcpy(data(), msg_->data(), size());
        }

        using super::data;

        using super::size;

        inline QByteArray toByteArray()
        {
            return QByteArray((const char *)data(), size());
        }
    };

    // An instance of this class cannot directly be created. Use one
    // of the 'ZMQContext::createSocket()' methods instead.
    class ZMQSocket : public QObject, private zmq::socket_t
    {
        Q_OBJECT

        friend class ZMQContext;

        typedef QObject qsuper;
        typedef zmq::socket_t zmqsuper;

    public:
        using zmqsuper::operator void *;

        using zmqsuper::close;

        inline void setOption(int option_, const void *optionVal_, size_t optionValLen_)
        {
            zmqsuper::setsockopt(option_, optionVal_, optionValLen_);
        }

        inline void setOption(int optName_, const char* str_) {
            setOption(optName_, str_, strlen(str_));
        }

        inline void setOption(int optName_, const QByteArray& bytes_) {
            setOption(optName_, bytes_.constData(), bytes_.size());
        }

        inline void setOption(int optName_, int value_) {
            setOption(optName_, &value_, sizeof(value_));
        }

        inline void getOption(int option_, void *optval_, size_t *optvallen_)
        {
            zmqsuper::getsockopt(option_, optval_, optvallen_);
        }

        inline void bindTo(const QString& addr_)
        {
            zmqsuper::bind(addr_.toLocal8Bit());
        }

        inline void bindTo(const char *addr_)
        {
            zmqsuper::bind(addr_);
        }

        inline void connectTo(const QString& addr_)
        {
            zmqsuper::connect(addr_.toLocal8Bit());
        }

        inline void connectTo(const char* addr_)
        {
            zmqsuper::connect(addr_);
        }

        inline bool sendMessage(ZMQMessage& msg_, int flags_ = ZMQ_NOBLOCK)
        {
            return zmqsuper::send(msg_, flags_);
        }

        inline bool sendMessage(const QByteArray& bytes_, int flags_ = ZMQ_NOBLOCK) {
            ZMQMessage msg(bytes_);
            bool result = send(msg, flags_);
            if (!result)
            {
                socketNotifyWrite_->setEnabled(true);
            }
            return result;
        }

        // Interprets the provided list of byte arrays as a multi-part message
        // and sends them accordingly.
        // If an empty list is provided this method doesn't do anything and returns trua.
        inline bool sendMessage(const QList<QByteArray>& msg_, int flags_ = ZMQ_NOBLOCK)
        {
            int i;
            for (i = 0; i < msg_.size() - 1; i++)
            {
                if (!sendMessage(msg_[i], flags_ | ZMQ_SNDMORE))
                    return false;
            }
            if (i < msg_.size())
                return sendMessage(msg_[i], flags_);

            return true;
        }

        // Receives a message or a message part.
        inline bool receiveMessage(ZMQMessage* msg_, int flags_ = ZMQ_NOBLOCK)
        {
            return zmqsuper::recv(msg_, flags_);
        }

        // Receives a message.
        // The message is represented as a list of byte arrays representing
        // a message's parts. If the message is not a multi-part message the
        // list will only contain one array.
        inline QList<QByteArray> receiveMessage()
        {
            QList<QByteArray> parts;

            ZMQMessage msg;
            while (receiveMessage(&msg))
            {
                parts += msg.toByteArray();
                msg.rebuild();

                if (!hasMoreMessageParts())
                    break;
            }

            return parts;
        }

        // Receives all messages currently available.
        // Each message is represented as a list of byte arrays representing the messages
        // and their parts in case of multi-part messages. If a message isn't a multi-part
        // message the corresponding byte array list will only contain one element.
        // Note that this method won't work with REQ-REP protocol.
        inline QList< QList<QByteArray> > receiveMessages()
        {
            QList< QList<QByteArray> > ret;

            QList<QByteArray> parts = receiveMessage();
            while (!parts.isEmpty())
            {
                ret += parts;

                parts = receiveMessage();
            }

            return ret;
        }

        inline int fileDescriptor()
        {
            int value;
            size_t size = sizeof(value);
            getOption(ZMQ_FD, &value, &size);
            return value;
        }

        inline quint32 flags()
        {
            quint32 value;
            size_t size = sizeof(value);
            getOption(ZMQ_EVENTS, &value, &size);
            return value;
        }

        // Returns true if there are more parts of a multi-part message
        // to be received.
        inline bool hasMoreMessageParts()
        {
            quint64 value;
            size_t size = sizeof(value);
            getOption(ZMQ_RCVMORE, &value, &size);
            return value;
        }

        inline void setIdentity(const char* nameStr_)
        {
            setOption(ZMQ_IDENTITY, nameStr_);
        }

        inline void setIdentity(const QString& name_)
        {
            setOption(ZMQ_IDENTITY, name_.toLocal8Bit());
        }

        inline void setIdentity(const QByteArray& name_)
        {
            setOption(ZMQ_IDENTITY, const_cast<char*>(name_.constData()), name_.size());
        }

        inline QByteArray identity()
        {
            char idbuf[256];
            size_t size = sizeof(idbuf);
            getOption(ZMQ_IDENTITY, idbuf, &size);
            return QByteArray(idbuf, size);
        }

        inline void setLinger(int msec_)
        {
            setOption(ZMQ_LINGER, msec_);
        }

        inline int linger()
        {
            int msec=-1;
            size_t size = sizeof(msec);
            getOption(ZMQ_LINGER, &msec, &size);
            return msec;
        }

        inline void subscribeTo(const char* filterStr_)
        {
            setOption(ZMQ_SUBSCRIBE, filterStr_);
        }

        inline void subscribeTo(const QString& filter_)
        {
            setOption(ZMQ_SUBSCRIBE, filter_.toLocal8Bit());
        }

        inline void subscribeTo(const QByteArray& filter_)
        {
            setOption(ZMQ_SUBSCRIBE, filter_);
        }

        inline void unsubscribeFrom(const char* filterStr_)
        {
            setOption(ZMQ_UNSUBSCRIBE, filterStr_);
        }

        inline void unsubscribeFrom(const QString& filter_)
        {
            setOption(ZMQ_UNSUBSCRIBE, filter_.toLocal8Bit());
        }

        inline void unsubscribeFrom(const QByteArray& filter_)
        {
            setOption(ZMQ_UNSUBSCRIBE, filter_);
        }

    protected:
        inline ZMQSocket(zmq::context_t* context_, int type_)
            : qsuper(0), zmqsuper(*context_, type_)
        {
            int fd = fileDescriptor();

            socketNotifyRead_ = new QSocketNotifier(fd, QSocketNotifier::Read, this);
            qsuper::connect(socketNotifyRead_, SIGNAL(activated(int)), this, SLOT(socketReadActivity()));

            socketNotifyWrite_ = new QSocketNotifier(fd, QSocketNotifier::Write, this);
            qsuper::connect(socketNotifyWrite_, SIGNAL(activated(int)), this, SLOT(socketWriteActivity()));
        }

        void socketActivity(quint32 flags_)
        {
            if(flags_ & ZMQ_POLLIN) {
                emit readyRead();
            }
            if(flags_ & ZMQ_POLLOUT) {
                emit readyWrite();
            }
            if(flags_ & ZMQ_POLLERR) {
                emit pollError();
            }
        }

    signals:
        void readyRead();
        void readyWrite();
        void pollError();

    protected slots:
        inline void socketReadActivity()
        {
            quint32 flags_ = flags();
            socketActivity(flags_);
        }

        inline void socketWriteActivity()
        {
            quint32 flags_ = flags();
            if (flags_ == 0)
            {
                socketNotifyWrite_->setEnabled(false);
            }
            socketActivity(flags_);
        }

    private:
        QSocketNotifier *socketNotifyRead_;
        QSocketNotifier *socketNotifyWrite_;
    };

    class ZMQContext : public QObject, private zmq::context_t
    {
        Q_OBJECT

        typedef QObject qsuper;
        typedef zmq::context_t zmqsuper;

    public:
        inline ZMQContext(int io_threads_, QObject* parent_ = 0) : qsuper(parent_), zmqsuper(io_threads_) {}

        // Deleting children is necessary, because otherwise the children are deleted after the context
        // which results in a blocking state. So we delete the children before the zmq::context_t
        // destructor implementation is called.
        inline ~ZMQContext()
        {
            QObjectList children_ = children();
            foreach (QObject* child, children_)
                delete child;
        }

        using zmqsuper::operator void*;

        // Creates a socket instance with the specified type.
        // The created instance will have this context set as its parent,
        // so deleting this context will first delete the socket.
        // You can call 'ZMQSocket::setParent()' method to change ownership,
        // but then you need to make sure the socket instance is deleted
        // before its context. Otherwise, you might encounter blocking
        // behavior.
        inline ZMQSocket* createSocket(int type_)
        {
            return createSocket(type_, this);
        }

        // Creates a socket instance with the specified type and parent.
        // The created instance will have this context set as its parent.
        // You can also call 'ZMQSocket::setParent()' method to change
        // ownership later on, but then you need to make sure the socket
        // instance is deleted before its context. Otherwise, you might
        // encounter blocking behavior.
        inline virtual ZMQSocket* createSocket(int type_, QObject* parent_)
        {
            ZMQSocket* socket = new ZMQSocket(this, type_);
            socket->setParent(parent_);
            return socket;
        }
    };
}

#endif // NZMQT_H
<commit_msg>refactoring: Introduced intermediate 'ZMQSocketBase' class and made getter methods const.<commit_after>// Copyright 2011 Johann Duscher. 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.
//
// THIS SOFTWARE IS PROVIDED BY JOHANN DUSCHER ''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 <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.
//
// The views and conclusions contained in the software and documentation are those of the
// authors and should not be interpreted as representing official policies, either expressed
// or implied, of Johann Duscher.

#ifndef NZMQT_H
#define NZMQT_H

#include <zmq.hpp>

#include <QObject>
#include <QList>
#include <QByteArray>
#include <QSocketNotifier>

namespace nzmqt
{
    typedef zmq::free_fn free_fn;
    typedef zmq::pollitem_t pollitem_t;

    typedef zmq::error_t ZMQException;

    using zmq::poll;
    using zmq::device;
    using zmq::version;

    class ZMQMessage : private zmq::message_t
    {
        friend class ZMQSocketBase;

        typedef zmq::message_t super;

    public:
        inline ZMQMessage() : super() {}

        inline ZMQMessage(size_t size_) : super(size_) {}

        inline ZMQMessage(void* data_, size_t size_, free_fn *ffn_, void* hint_ = 0)
            : super(data_, size_, ffn_, hint_) {}

        inline ZMQMessage(const QByteArray& b) : super(b.size()) {
            memcpy(data(), b.constData(), b.size());
        }

        using super::rebuild;

        inline void move(ZMQMessage* msg_)
        {
            super::move(static_cast<zmq::message_t*>(msg_));
        }

        inline void copy(ZMQMessage* msg_)
        {
            super::copy(msg_);
        }

        inline void clone(ZMQMessage* msg_)
        {
            rebuild(msg_->size());
            memcpy(data(), msg_->data(), size());
        }

        using super::data;

        using super::size;

        inline QByteArray toByteArray()
        {
            return QByteArray((const char *)data(), size());
        }
    };

    // This class cannot be instantiated. Its purpose is to serve as an
    // intermediate base class that provides Qt-based convenience methods
    // to subclasses.
    class ZMQSocketBase : private zmq::socket_t
    {
        typedef zmq::socket_t zmqsuper;

    public:
        using zmqsuper::operator void *;

        using zmqsuper::close;

        inline void setOption(int option_, const void *optionVal_, size_t optionValLen_)
        {
            setsockopt(option_, optionVal_, optionValLen_);
        }

        inline void setOption(int optName_, const char* str_) {
            setOption(optName_, str_, strlen(str_));
        }

        inline void setOption(int optName_, const QByteArray& bytes_) {
            setOption(optName_, bytes_.constData(), bytes_.size());
        }

        inline void setOption(int optName_, int value_) {
            setOption(optName_, &value_, sizeof(value_));
        }

        inline void getOption(int option_, void *optval_, size_t *optvallen_) const
        {
            const_cast<ZMQSocketBase*>(this)->getsockopt(option_, optval_, optvallen_);
        }

        inline void bindTo(const QString& addr_)
        {
            bind(addr_.toLocal8Bit());
        }

        inline void bindTo(const char *addr_)
        {
            bind(addr_);
        }

        inline void connectTo(const QString& addr_)
        {
            connect(addr_.toLocal8Bit());
        }

        inline void connectTo(const char* addr_)
        {
            connect(addr_);
        }

        inline bool sendMessage(ZMQMessage& msg_, int flags_ = ZMQ_NOBLOCK)
        {
            return send(msg_, flags_);
        }

        inline bool sendMessage(const QByteArray& bytes_, int flags_ = ZMQ_NOBLOCK)
        {
            ZMQMessage msg(bytes_);
            return send(msg, flags_);
        }

        // Interprets the provided list of byte arrays as a multi-part message
        // and sends them accordingly.
        // If an empty list is provided this method doesn't do anything and returns trua.
        inline bool sendMessage(const QList<QByteArray>& msg_, int flags_ = ZMQ_NOBLOCK)
        {
            int i;
            for (i = 0; i < msg_.size() - 1; i++)
            {
                if (!sendMessage(msg_[i], flags_ | ZMQ_SNDMORE))
                    return false;
            }
            if (i < msg_.size())
                return sendMessage(msg_[i], flags_);

            return true;
        }

        // Receives a message or a message part.
        inline bool receiveMessage(ZMQMessage* msg_, int flags_ = ZMQ_NOBLOCK)
        {
            return recv(msg_, flags_);
        }

        // Receives a message.
        // The message is represented as a list of byte arrays representing
        // a message's parts. If the message is not a multi-part message the
        // list will only contain one array.
        inline QList<QByteArray> receiveMessage()
        {
            QList<QByteArray> parts;

            ZMQMessage msg;
            while (receiveMessage(&msg))
            {
                parts += msg.toByteArray();
                msg.rebuild();

                if (!hasMoreMessageParts())
                    break;
            }

            return parts;
        }

        // Receives all messages currently available.
        // Each message is represented as a list of byte arrays representing the messages
        // and their parts in case of multi-part messages. If a message isn't a multi-part
        // message the corresponding byte array list will only contain one element.
        // Note that this method won't work with REQ-REP protocol.
        inline QList< QList<QByteArray> > receiveMessages()
        {
            QList< QList<QByteArray> > ret;

            QList<QByteArray> parts = receiveMessage();
            while (!parts.isEmpty())
            {
                ret += parts;

                parts = receiveMessage();
            }

            return ret;
        }

        inline int fileDescriptor() const
        {
            int value;
            size_t size = sizeof(value);
            getOption(ZMQ_FD, &value, &size);
            return value;
        }

        inline quint32 flags() const
        {
            quint32 value;
            size_t size = sizeof(value);
            getOption(ZMQ_EVENTS, &value, &size);
            return value;
        }

        // Returns true if there are more parts of a multi-part message
        // to be received.
        inline bool hasMoreMessageParts() const
        {
            quint64 value;
            size_t size = sizeof(value);
            getOption(ZMQ_RCVMORE, &value, &size);
            return value;
        }

        inline void setIdentity(const char* nameStr_)
        {
            setOption(ZMQ_IDENTITY, nameStr_);
        }

        inline void setIdentity(const QString& name_)
        {
            setOption(ZMQ_IDENTITY, name_.toLocal8Bit());
        }

        inline void setIdentity(const QByteArray& name_)
        {
            setOption(ZMQ_IDENTITY, const_cast<char*>(name_.constData()), name_.size());
        }

        inline QByteArray identity() const
        {
            char idbuf[256];
            size_t size = sizeof(idbuf);
            getOption(ZMQ_IDENTITY, idbuf, &size);
            return QByteArray(idbuf, size);
        }

        inline void setLinger(int msec_)
        {
            setOption(ZMQ_LINGER, msec_);
        }

        inline int linger() const
        {
            int msec=-1;
            size_t size = sizeof(msec);
            getOption(ZMQ_LINGER, &msec, &size);
            return msec;
        }

        inline void subscribeTo(const char* filterStr_)
        {
            setOption(ZMQ_SUBSCRIBE, filterStr_);
        }

        inline void subscribeTo(const QString& filter_)
        {
            setOption(ZMQ_SUBSCRIBE, filter_.toLocal8Bit());
        }

        inline void subscribeTo(const QByteArray& filter_)
        {
            setOption(ZMQ_SUBSCRIBE, filter_);
        }

        inline void unsubscribeFrom(const char* filterStr_)
        {
            setOption(ZMQ_UNSUBSCRIBE, filterStr_);
        }

        inline void unsubscribeFrom(const QString& filter_)
        {
            setOption(ZMQ_UNSUBSCRIBE, filter_.toLocal8Bit());
        }

        inline void unsubscribeFrom(const QByteArray& filter_)
        {
            setOption(ZMQ_UNSUBSCRIBE, filter_);
        }

    protected:
        inline ZMQSocketBase(zmq::context_t* context_, int type_)
            : zmqsuper(*context_, type_)
        {
        }
    };

    // An instance of this class cannot directly be created. Use one
    // of the 'ZMQContext::createSocket()' factory methods instead.
    class ZMQSocket : public QObject, public ZMQSocketBase
    {
        Q_OBJECT

        friend class ZMQContext;

        typedef QObject qsuper;
        typedef ZMQSocketBase zmqsuper;

    public:
        using zmqsuper::sendMessage;

        inline bool sendMessage(const QByteArray& bytes_, int flags_ = ZMQ_NOBLOCK)
        {
            bool result = zmqsuper::sendMessage(bytes_, flags_);

            if (!result)
                socketNotifyWrite_->setEnabled(true);

            return result;
        }

    protected:
        inline ZMQSocket(zmq::context_t* context_, int type_)
            : qsuper(0), zmqsuper(context_, type_)
        {
            int fd = fileDescriptor();

            socketNotifyRead_ = new QSocketNotifier(fd, QSocketNotifier::Read, this);
            qsuper::connect(socketNotifyRead_, SIGNAL(activated(int)), this, SLOT(socketReadActivity()));

            socketNotifyWrite_ = new QSocketNotifier(fd, QSocketNotifier::Write, this);
            qsuper::connect(socketNotifyWrite_, SIGNAL(activated(int)), this, SLOT(socketWriteActivity()));
        }

        inline void socketActivity(quint32 flags_)
        {
            if(flags_ & ZMQ_POLLIN) {
                emit readyRead();
            }
            if(flags_ & ZMQ_POLLOUT) {
                emit readyWrite();
            }
            if(flags_ & ZMQ_POLLERR) {
                emit pollError();
            }
        }

    signals:
        void readyRead();
        void readyWrite();
        void pollError();

    protected slots:
        inline void socketReadActivity()
        {
            quint32 flags_ = flags();
            socketActivity(flags_);
        }

        inline void socketWriteActivity()
        {
            quint32 flags_ = flags();
            if (flags_ == 0)
            {
                socketNotifyWrite_->setEnabled(false);
            }
            socketActivity(flags_);
        }

    private:
        QSocketNotifier *socketNotifyRead_;
        QSocketNotifier *socketNotifyWrite_;
    };

    class ZMQContext : public QObject, private zmq::context_t
    {
        Q_OBJECT

        typedef QObject qsuper;
        typedef zmq::context_t zmqsuper;

    public:
        inline ZMQContext(int io_threads_, QObject* parent_ = 0) : qsuper(parent_), zmqsuper(io_threads_) {}

        // Deleting children is necessary, because otherwise the children are deleted after the context
        // which results in a blocking state. So we delete the children before the zmq::context_t
        // destructor implementation is called.
        inline ~ZMQContext()
        {
            QObjectList children_ = children();
            foreach (QObject* child, children_)
                delete child;
        }

        using zmqsuper::operator void*;

        // Creates a socket instance with the specified type.
        // The created instance will have this context set as its parent,
        // so deleting this context will first delete the socket.
        // You can call 'ZMQSocket::setParent()' method to change ownership,
        // but then you need to make sure the socket instance is deleted
        // before its context. Otherwise, you might encounter blocking
        // behavior.
        inline ZMQSocket* createSocket(int type_)
        {
            return createSocket(type_, this);
        }

        // Creates a socket instance with the specified type and parent.
        // The created instance will have this context set as its parent.
        // You can also call 'ZMQSocket::setParent()' method to change
        // ownership later on, but then you need to make sure the socket
        // instance is deleted before its context. Otherwise, you might
        // encounter blocking behavior.
        inline virtual ZMQSocket* createSocket(int type_, QObject* parent_)
        {
            ZMQSocket* socket = new ZMQSocket(this, type_);
            socket->setParent(parent_);
            return socket;
        }
    };
}

#endif // NZMQT_H
<|endoftext|>


<commit_before><commit_msg>LGTM: Move seq->next out of loop control<commit_after><|endoftext|>


<commit_before>// Copyright Hugh Perkins 2015 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include "NormalizationHelper.h"
#include "NeuralNet.h"

#include "BatchLearner.h"

using namespace std;

#undef STATIC
#undef VIRTUAL
#define STATIC
#define VIRTUAL

template< typename T>
void NetLearnLabeledBatch<T>::run( NeuralNet *net, T *batchData, int *batchLabels ) {
    net->learnBatchFromLabels( learningRate, batchData, batchLabels );
}

template< typename T>
void NetPropagateBatch<T>::run( NeuralNet *net, T *batchData, int *batchLabels ) {
    net->propagate( batchData );
}

template< typename T > BatchLearner<T>::BatchLearner( NeuralNet *net ) :
    net( net ) {
}

template< typename T > EpochResult BatchLearner<T>::batchedNetAction( int batchSize, int N, T *data, int *labels, NetAction<T> *netAction ) {
    int numRight = 0;
    float loss = 0;
    net->setBatchSize( batchSize );
    int numBatches = (N + batchSize - 1 ) / batchSize;
    int inputCubeSize = net->getInputCubeSize();
//    float *batchData = new float[ batchSize * inputCubeSize ];
    for( int batch = 0; batch < numBatches; batch++ ) {
        int batchStart = batch * batchSize;
        int thisBatchSize = batchSize;
        if( batch == numBatches - 1 ) {
            thisBatchSize = N - batchStart;
            net->setBatchSize( thisBatchSize );
        }
        const int batchInputSize = thisBatchSize * inputCubeSize;
        T *thisBatchData = data + batchStart * inputCubeSize;
//        for( int i = 0; i < batchInputSize; i++ ) {
//            batchData[i] = thisBatchData[i];
//        }
        netAction->run( net, thisBatchData, &(labels[batchStart]) );
        loss += net->calcLossFromLabels( &(labels[batchStart]) );
        numRight += net->calcNumRight( &(labels[batchStart]) );
    }
//    delete[] batchData;
    EpochResult epochResult( loss, numRight );
    return epochResult;
}

template< typename T > int BatchLearner<T>::test( int batchSize, int N, T *testData, int *testLabels ) {
    NetAction<T> *action = new NetPropagateBatch<T>();
    int numRight = batchedNetAction( batchSize, N, testData, testLabels, action ).numRight;
    delete action;
    return numRight;
}

template< typename T > EpochResult BatchLearner<T>::runEpochFromLabels( float learningRate, int batchSize, int Ntrain, T *trainData, int *trainLabels ) {
    NetAction<T> *action = new NetLearnLabeledBatch<T>( learningRate );
    EpochResult epochResult = batchedNetAction( batchSize, Ntrain, trainData, trainLabels, action );
    delete action;
    return epochResult;
}

template class BatchLearner<unsigned char>;
template class BatchLearner<float>;

<commit_msg>simplify batchlearner<commit_after>// Copyright Hugh Perkins 2015 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include "NormalizationHelper.h"
#include "NeuralNet.h"

#include "BatchLearner.h"

using namespace std;

#undef STATIC
#undef VIRTUAL
#define STATIC
#define VIRTUAL

template< typename T>
void NetLearnLabeledBatch<T>::run( NeuralNet *net, T *batchData, int *batchLabels ) {
    net->learnBatchFromLabels( learningRate, batchData, batchLabels );
}

template< typename T>
void NetPropagateBatch<T>::run( NeuralNet *net, T *batchData, int *batchLabels ) {
    net->propagate( batchData );
}

template< typename T > BatchLearner<T>::BatchLearner( NeuralNet *net ) :
    net( net ) {
}

template< typename T > EpochResult BatchLearner<T>::batchedNetAction( int batchSize, int N, T *data, int *labels, NetAction<T> *netAction ) {
    int numRight = 0;
    float loss = 0;
    net->setBatchSize( batchSize );
    int numBatches = (N + batchSize - 1 ) / batchSize;
    int inputCubeSize = net->getInputCubeSize();
    for( int batch = 0; batch < numBatches; batch++ ) {
        int batchStart = batch * batchSize;
        if( batch == numBatches - 1 ) {
            net->setBatchSize( N - batchStart );
        }
        netAction->run( net, &(data[ batchStart * inputCubeSize ]), &(labels[batchStart]) );
        loss += net->calcLossFromLabels( &(labels[batchStart]) );
        numRight += net->calcNumRight( &(labels[batchStart]) );
    }
    EpochResult epochResult( loss, numRight );
    return epochResult;
}

template< typename T > int BatchLearner<T>::test( int batchSize, int N, T *testData, int *testLabels ) {
    NetAction<T> *action = new NetPropagateBatch<T>();
    int numRight = batchedNetAction( batchSize, N, testData, testLabels, action ).numRight;
    delete action;
    return numRight;
}

template< typename T > EpochResult BatchLearner<T>::runEpochFromLabels( float learningRate, int batchSize, int Ntrain, T *trainData, int *trainLabels ) {
    NetAction<T> *action = new NetLearnLabeledBatch<T>( learningRate );
    EpochResult epochResult = batchedNetAction( batchSize, Ntrain, trainData, trainLabels, action );
    delete action;
    return epochResult;
}

template class BatchLearner<unsigned char>;
template class BatchLearner<float>;

<|endoftext|>


<commit_before>#include "eyesore.h"

using namespace eyesore;

int main(void)
{
	Engine e;

	e.makeWindow(400, 300, "eyesore", false);
	e.run();

	return 0;
}

<commit_msg>Test everything in driver<commit_after>#include <glm/glm.hpp>

#include "eyesore.h"
#include "Scene.h"
#include "Model.h"

using namespace eyesore;
using namespace glm;

int main(void)
{
	Camera c(vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, -1.0f), 4.0f/3.0f);
	Engine e(c);
	Scene s;

	e.makeWindow(400, 300, "eyesore", false);
	s.add(Model("../models/teapot.obj"));
	e.setScene(s);
	e.run();

	return 0;
}

<|endoftext|>


<commit_before>#ifndef __RANK_FILTER__
#define __RANK_FILTER__

#include <deque>
#include <cassert>
#include <functional>
#include <iostream>
#include <iterator>

#include <boost/array.hpp>
#include <boost/container/set.hpp>
#include <boost/container/node_allocator.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>

namespace rank_filter
{

template<class I1,
         class I2>
inline void lineRankOrderFilter1D(const I1& src_begin, const I1& src_end,
        I2& dest_begin, I2& dest_end,
        size_t half_length, double rank)
{
    // Types in use.
    typedef typename std::iterator_traits<I1>::value_type T1;
    typedef typename std::iterator_traits<I2>::value_type T2;
    typedef typename std::iterator_traits<I1>::difference_type I1_diff_t;
    typedef typename std::iterator_traits<I2>::difference_type I2_diff_t;

    // Establish common types to work with source and destination values.
    BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
    typedef T1 T;
    typedef typename boost::common_type<I1_diff_t, I2_diff_t>::type I_diff_t;

    // Define container types that will be used.
    typedef boost::container::multiset< T,
            std::less<T>,
            boost::container::node_allocator<T>,
            boost::container::tree_assoc_options< boost::container::tree_type<boost::container::scapegoat_tree> >::type> multiset;
    typedef std::deque< typename multiset::iterator > deque;

    // Lengths.
    const I_diff_t src_size = std::distance(src_begin, src_end);
    const I_diff_t dest_size = std::distance(dest_begin, dest_end);

    // Ensure the result will fit.
    assert(src_size <= dest_size);

    // Window length cannot exceed input data with reflection.
    assert((half_length + 1) <= src_size);

    // Rank must be in the range 0 to 1.
    assert((0 <= rank) && (rank <= 1));

    // The position of the window.
    I_diff_t window_begin = 0;

    // Find window offset corresponding to this rank.
    const I_diff_t rank_pos = static_cast<I_diff_t>(boost::math::round(rank * (2 * half_length)));

    // Track values in window both in sorted and sequential order.
    multiset sorted_window;
    deque window_iters(2 * half_length + 1);

    // Get the initial sorted window.
    // Include the reflection.
    for (I_diff_t j = 0; j < half_length; j++)
    {
        window_iters[j] = sorted_window.insert(src_begin[window_begin + half_length - j]);
    }
    for (I_diff_t j = half_length; j < (2 * half_length + 1); j++)
    {
        window_iters[j] = sorted_window.insert(src_begin[window_begin + j - half_length]);
    }

    typename multiset::iterator rank_point = sorted_window.begin();

    for (I_diff_t i = 0; i < rank_pos; i++)
    {
        rank_point++;
    }

    typename multiset::iterator prev_iter;
    T prev_value;
    T next_value;
    while ( window_begin < src_size )
    {
        dest_begin[window_begin] = *rank_point;

        prev_iter = window_iters.front();
        prev_value = *prev_iter;
        window_iters.pop_front();

        window_begin++;

        if ( window_begin == src_size )
        {
            next_value = prev_value;
        }
        else if ( window_begin < (src_size - half_length) )
        {
            next_value = src_begin[window_begin + half_length];
        }
        else
        {
            next_value = *(window_iters[(2 * (src_size - (window_begin + 1)))]);
        }

        if ( ( *rank_point < prev_value ) && ( *rank_point <= next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));
        }
        else if ( ( *rank_point >= prev_value ) && ( *rank_point > next_value ) )
        {
            if ( rank_point == prev_iter )
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point--;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));
            }
        }
        else if ( ( *rank_point < prev_value ) && ( *rank_point > next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));

            rank_point--;
        }
        else if ( ( *rank_point >= prev_value ) && ( *rank_point <= next_value ) )
        {
            if (rank_point == prev_iter)
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point++;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));

                rank_point++;
            }
        }
    }
}

}

namespace std
{
    template <class T, size_t N>
    ostream& operator<<(ostream& out, const boost::array<T, N>& that)
    {
        out << "{ ";
        for (unsigned int i = 0; i < (N - 1); i++)
        {
            out << that[i] << ", ";
        }
        out << that[N - 1] << " }";

        return(out);
    }
}

#endif //__RANK_FILTER__
<commit_msg>Define `rank_point` near `rank_pos`<commit_after>#ifndef __RANK_FILTER__
#define __RANK_FILTER__

#include <deque>
#include <cassert>
#include <functional>
#include <iostream>
#include <iterator>

#include <boost/array.hpp>
#include <boost/container/set.hpp>
#include <boost/container/node_allocator.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>

namespace rank_filter
{

template<class I1,
         class I2>
inline void lineRankOrderFilter1D(const I1& src_begin, const I1& src_end,
        I2& dest_begin, I2& dest_end,
        size_t half_length, double rank)
{
    // Types in use.
    typedef typename std::iterator_traits<I1>::value_type T1;
    typedef typename std::iterator_traits<I2>::value_type T2;
    typedef typename std::iterator_traits<I1>::difference_type I1_diff_t;
    typedef typename std::iterator_traits<I2>::difference_type I2_diff_t;

    // Establish common types to work with source and destination values.
    BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
    typedef T1 T;
    typedef typename boost::common_type<I1_diff_t, I2_diff_t>::type I_diff_t;

    // Define container types that will be used.
    typedef boost::container::multiset< T,
            std::less<T>,
            boost::container::node_allocator<T>,
            boost::container::tree_assoc_options< boost::container::tree_type<boost::container::scapegoat_tree> >::type> multiset;
    typedef std::deque< typename multiset::iterator > deque;

    // Lengths.
    const I_diff_t src_size = std::distance(src_begin, src_end);
    const I_diff_t dest_size = std::distance(dest_begin, dest_end);

    // Ensure the result will fit.
    assert(src_size <= dest_size);

    // Window length cannot exceed input data with reflection.
    assert((half_length + 1) <= src_size);

    // Rank must be in the range 0 to 1.
    assert((0 <= rank) && (rank <= 1));

    // The position of the window.
    I_diff_t window_begin = 0;

    // Find window offset corresponding to this rank.
    const I_diff_t rank_pos = static_cast<I_diff_t>(boost::math::round(rank * (2 * half_length)));
    typename multiset::iterator rank_point;

    // Track values in window both in sorted and sequential order.
    multiset sorted_window;
    deque window_iters(2 * half_length + 1);

    // Get the initial sorted window.
    // Include the reflection.
    for (I_diff_t j = 0; j < half_length; j++)
    {
        window_iters[j] = sorted_window.insert(src_begin[window_begin + half_length - j]);
    }
    for (I_diff_t j = half_length; j < (2 * half_length + 1); j++)
    {
        window_iters[j] = sorted_window.insert(src_begin[window_begin + j - half_length]);
    }

    rank_point = sorted_window.begin();

    for (I_diff_t i = 0; i < rank_pos; i++)
    {
        rank_point++;
    }

    typename multiset::iterator prev_iter;
    T prev_value;
    T next_value;
    while ( window_begin < src_size )
    {
        dest_begin[window_begin] = *rank_point;

        prev_iter = window_iters.front();
        prev_value = *prev_iter;
        window_iters.pop_front();

        window_begin++;

        if ( window_begin == src_size )
        {
            next_value = prev_value;
        }
        else if ( window_begin < (src_size - half_length) )
        {
            next_value = src_begin[window_begin + half_length];
        }
        else
        {
            next_value = *(window_iters[(2 * (src_size - (window_begin + 1)))]);
        }

        if ( ( *rank_point < prev_value ) && ( *rank_point <= next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));
        }
        else if ( ( *rank_point >= prev_value ) && ( *rank_point > next_value ) )
        {
            if ( rank_point == prev_iter )
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point--;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));
            }
        }
        else if ( ( *rank_point < prev_value ) && ( *rank_point > next_value ) )
        {
            sorted_window.erase(prev_iter);
            window_iters.push_back(sorted_window.insert(next_value));

            rank_point--;
        }
        else if ( ( *rank_point >= prev_value ) && ( *rank_point <= next_value ) )
        {
            if (rank_point == prev_iter)
            {
                window_iters.push_back(sorted_window.insert(next_value));
                rank_point++;

                sorted_window.erase(prev_iter);
            }
            else
            {
                sorted_window.erase(prev_iter);
                window_iters.push_back(sorted_window.insert(next_value));

                rank_point++;
            }
        }
    }
}

}

namespace std
{
    template <class T, size_t N>
    ostream& operator<<(ostream& out, const boost::array<T, N>& that)
    {
        out << "{ ";
        for (unsigned int i = 0; i < (N - 1); i++)
        {
            out << that[i] << ", ";
        }
        out << that[N - 1] << " }";

        return(out);
    }
}

#endif //__RANK_FILTER__
<|endoftext|>


<commit_before>// @(#)root/tree:$Name:  $:$Id: TTreeCache.cxx,v 1.12 2007/01/03 18:50:36 pcanal Exp $
// Author: Rene Brun   04/06/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TTreeCache                                                           //
//                                                                      //
//  A specialized TFileCacheRead object for a TTree                     //
//  This class acts as a file cache, registering automatically the      //
//  baskets from the branches being processed (TTree::Draw or           //
//  TTree::Process and TSelectors) when in the learning phase.          //
//  The learning phase is by default 100 entries.                       //
//  It can be changed via TTreeCache::SetLearnEntries.                  //
//                                                                      //
//  This cache speeds-up considerably the performance, in particular    //
//  when the Tree is accessed remotely via a high latency network.      //
//                                                                      //
//  The default cache size (10 Mbytes) may be changed via the function  //
//      TTreeCache::SetCacheSize                                        //
//                                                                      //
//  Only the baskets for the requested entry range are put in the cache //
//                                                                      //
//  For each Tree being processed a TTreeCache object is created.       //
//  This object is automatically deleted when the Tree is deleted or    //
//  when the file is deleted.                                           //
//                                                                      //
//  -Special case of a TChain                                           //
//   Once the training is done on the first Tree, the list of branches  //
//   in the cache is kept for the following files.                      //
//                                                                      //
//  -Special case of a TEventlist                                       //
//   if the Tree or TChain has a TEventlist, only the buffers           //
//   referenced by the list are put in the cache.                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTreeCache.h"
#include "TChain.h"
#include "TList.h"
#include "TBranch.h"
#include "TEventList.h"
#include "TObjString.h"

Int_t TTreeCache::fgLearnEntries = 100;

ClassImp(TTreeCache)

//______________________________________________________________________________
TTreeCache::TTreeCache() : TFileCacheRead(),
   fEntryMin(0),
   fEntryMax(1),
   fEntryNext(1),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(0),
   fOwner(0),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Default Constructor.
}

//______________________________________________________________________________
TTreeCache::TTreeCache(TTree *tree, Int_t buffersize) : TFileCacheRead(tree->GetCurrentFile(),buffersize),
   fEntryMin(0),
   fEntryMax(tree->GetEntriesFast()),
   fEntryNext(0),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(new TList),
   fOwner(tree),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Constructor.

   fEntryNext = fEntryMin + fgLearnEntries;
   Int_t nleaves = tree->GetListOfLeaves()->GetEntries();
   fBranches = new TBranch*[nleaves+10]; //add a margin just in case in a TChain?
}

//______________________________________________________________________________
TTreeCache::~TTreeCache()
{
   // destructor. (in general called by the TFile destructor

   delete [] fBranches;
   if (fBrNames) {fBrNames->Delete(); delete fBrNames; fBrNames=0;}
}

//_____________________________________________________________________________
void TTreeCache::AddBranch(TBranch *b)
{
   //add a branch to the list of branches to be stored in the cache
   //this function is called by TBranch::GetBasket

   if (!fIsLearning) return;

   //Is branch already in the cache?
   Bool_t isNew = kTRUE;
   for (int i=0;i<fNbranches;i++) {
      if (fBranches[i] == b) {isNew = kFALSE; break;}
   }
   if (isNew) {
      fTree = b->GetTree();
      fBranches[fNbranches] = b;
      fBrNames->Add(new TObjString(b->GetName()));
      fZipBytes += b->GetZipBytes();
      fNbranches++;
      if (gDebug > 0) printf("Entry: %lld, registering branch: %s\n",b->GetTree()->GetReadEntry(),b->GetName());
   }
}

//_____________________________________________________________________________
Bool_t TTreeCache::FillBuffer()
{
   // Fill the cache buffer with the branches in the cache.

   if (fNbranches <= 0) return kFALSE;
   TTree *tree = fBranches[0]->GetTree();
   Long64_t entry = tree->GetReadEntry();
   if (entry < fEntryNext) return kFALSE;

   // Estimate number of entries that can fit in the cache compare it
   // to the original value of fBufferSize not to the real one
   if (fZipBytes==0) {
      fEntryNext = entry + tree->GetEntries();;
   } else {
      fEntryNext = entry + tree->GetEntries()*fBufferSizeMin/fZipBytes;
   }
   if (fEntryMax <= 0) fEntryMax = tree->GetEntries();
   if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1;

   // Check if owner has a TEventList set. If yes we optimize for this
   // Special case reading only the baskets containing entries in the
   // list.
   TEventList *elist = fOwner->GetEventList();
   Long64_t chainOffset = 0;
   if (elist) {
      if (fOwner->IsA() ==TChain::Class()) {
         TChain *chain = (TChain*)fOwner;
         Int_t t = chain->GetTreeNumber();
         chainOffset = chain->GetTreeOffset()[t];
      }
   }

   //clear cache buffer
   TFileCacheRead::Prefetch(0,0);
   //store baskets
   Bool_t mustBreak = kFALSE;
   for (Int_t i=0;i<fNbranches;i++) {
      if (mustBreak) break;
      TBranch *b = fBranches[i];
      Int_t nb = b->GetMaxBaskets();
      Int_t *lbaskets   = b->GetBasketBytes();
      Long64_t *entries = b->GetBasketEntry();
      if (!lbaskets || !entries) continue;
      //we have found the branch. We now register all its baskets
      //from the requested offset to the basket below fEntrymax
      for (Int_t j=0;j<nb;j++) {
         Long64_t pos = b->GetBasketSeek(j);
         Int_t len = lbaskets[j];
         if (pos <= 0 || len <= 0) continue;
         if (entries[j] > fEntryNext) continue;
         if (entries[j] < entry && (j<nb-1 && entries[j+1] < entry)) continue;
         if (elist) {
            Long64_t emax = fEntryMax;
            if (j<nb-1) emax = entries[j+1]-1;
            if (!elist->ContainsRange(entries[j]+chainOffset,emax+chainOffset)) continue;
         }
         fNReadPref++;
         TFileCacheRead::Prefetch(pos,len);
         //we allow up to twice the default buffer size. When using eventlist in particular
         //it may happen that the evaluation of fEntryNext is bad, hence this protection
         if (fNtot > 2*fBufferSizeMin) {TFileCacheRead::Prefetch(0,0);mustBreak = kTRUE; break;}
      }
      if (gDebug > 0) printf("Entry: %lld, registering baskets branch %s, fEntryNext=%lld, fNseek=%d, fNtot=%d\n",entry,fBranches[i]->GetName(),fEntryNext,fNseek,fNtot);
   }
   fIsLearning = kFALSE;
   if (mustBreak) return kFALSE;
   return kTRUE;
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiency()
{
   // Give the total efficiency of the cache... defined as the ratio
   // of blocks found in the cache vs. the number of blocks prefetched
   // ( it could be more than 1 if we read the same block from the cache more
   //   than once )
   // Note: This should eb used at the end of the processing or we will
   //       get uncomplete stats

   if ( !fNReadPref )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)fNReadPref);
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiencyRel()
{
   // This will indicate a sort of relative efficiency... a ratio of the
   // reads found in the cache to the number of reads so far

   if ( !fNReadOk && !fNReadMiss )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)(fNReadOk + fNReadMiss));
}

//_____________________________________________________________________________
Int_t TTreeCache::GetLearnEntries()
{
   //static function returning the number of entries used to train the cache
   //see SetLearnEntries

   return fgLearnEntries;
}

//_____________________________________________________________________________
TTree *TTreeCache::GetTree() const
{
   //return Tree in the cache
   if (fNbranches <= 0) return 0;
   return fBranches[0]->GetTree();
}

//_____________________________________________________________________________
Int_t TTreeCache::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
   // Read buffer at position pos.
   // If pos is in the list of prefetched blocks read from fBuffer.
   // Otherwise try to fill the cache from the list of selected branches,
   // and recheck if pos is now in the list.
   // Returns
   //    -1 in case of read failure,
   //     0 in case not in cache,
   //     1 in case read from cache.
   // This function overloads TFileCacheRead::ReadBuffer.

   //Is request already in the cache?
   if (TFileCacheRead::ReadBuffer(buf,pos,len) == 1){
      fNReadOk++;
      return 1;
   }

   //not found in cache. Do we need to fill the cache?
   Bool_t bufferFilled = FillBuffer();
   if (bufferFilled) {
      Int_t res = TFileCacheRead::ReadBuffer(buf,pos,len);

      if (res == 1)
         fNReadOk++;
      else if (res == 0)
         fNReadMiss++;

      return res;
   }
   fNReadMiss++;

   return 0;
}

//_____________________________________________________________________________
void TTreeCache::SetEntryRange(Long64_t emin, Long64_t emax)
{
   // Set the minimum and maximum entry number to be processed
   // this information helps to optimize the number of baskets to read
   // when prefetching the branch buffers.

   fEntryMin  = emin;
   fEntryMax  = emax;
   fEntryNext  = fEntryMin + fgLearnEntries;
   if (gDebug > 0) printf("SetEntryRange: fEntryMin=%lld, fEntryMax=%lld, fEntryNext=%lld\n",fEntryMin,fEntryMax,fEntryNext);
   fIsLearning = kTRUE;
   fNbranches  = 0;
   fZipBytes   = 0;
   if (fBrNames) fBrNames->Delete();

}

//_____________________________________________________________________________
void TTreeCache::SetLearnEntries(Int_t n)
{
   // Static function to set the number of entries to be used in learning mode
   // The default value for n is 10. n must be >= 1

   if (n < 1) n = 1;
   fgLearnEntries = n;
}

//_____________________________________________________________________________
void TTreeCache::UpdateBranches(TTree *tree)
{
   //update pointer to current Tree and recompute pointers to the branches in the cache

   fTree = tree;

   fEntryMin  = 0;
   fEntryMax  = fTree->GetEntries();
   fEntryNext = fEntryMin + fgLearnEntries;
   fZipBytes  = 0;
   fNbranches = 0;
   TIter next(fBrNames);
   TObjString *os;
   while ((os = (TObjString*)next())) {
      TBranch *b = fTree->GetBranch(os->GetName());
      if (!b) continue;
      fBranches[fNbranches] = b;
      fZipBytes   += b->GetZipBytes();
      fNbranches++;
   }
}
<commit_msg>Reject request from TTree object other than the one that created the TTreeCache object<commit_after>// @(#)root/tree:$Name:  $:$Id: TTreeCache.cxx,v 1.13 2007/02/01 15:26:19 brun Exp $
// Author: Rene Brun   04/06/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TTreeCache                                                           //
//                                                                      //
//  A specialized TFileCacheRead object for a TTree                     //
//  This class acts as a file cache, registering automatically the      //
//  baskets from the branches being processed (TTree::Draw or           //
//  TTree::Process and TSelectors) when in the learning phase.          //
//  The learning phase is by default 100 entries.                       //
//  It can be changed via TTreeCache::SetLearnEntries.                  //
//                                                                      //
//  This cache speeds-up considerably the performance, in particular    //
//  when the Tree is accessed remotely via a high latency network.      //
//                                                                      //
//  The default cache size (10 Mbytes) may be changed via the function  //
//      TTreeCache::SetCacheSize                                        //
//                                                                      //
//  Only the baskets for the requested entry range are put in the cache //
//                                                                      //
//  For each Tree being processed a TTreeCache object is created.       //
//  This object is automatically deleted when the Tree is deleted or    //
//  when the file is deleted.                                           //
//                                                                      //
//  -Special case of a TChain                                           //
//   Once the training is done on the first Tree, the list of branches  //
//   in the cache is kept for the following files.                      //
//                                                                      //
//  -Special case of a TEventlist                                       //
//   if the Tree or TChain has a TEventlist, only the buffers           //
//   referenced by the list are put in the cache.                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTreeCache.h"
#include "TChain.h"
#include "TList.h"
#include "TBranch.h"
#include "TEventList.h"
#include "TObjString.h"

Int_t TTreeCache::fgLearnEntries = 100;

ClassImp(TTreeCache)

//______________________________________________________________________________
TTreeCache::TTreeCache() : TFileCacheRead(),
   fEntryMin(0),
   fEntryMax(1),
   fEntryNext(1),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(0),
   fOwner(0),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Default Constructor.
}

//______________________________________________________________________________
TTreeCache::TTreeCache(TTree *tree, Int_t buffersize) : TFileCacheRead(tree->GetCurrentFile(),buffersize),
   fEntryMin(0),
   fEntryMax(tree->GetEntriesFast()),
   fEntryNext(0),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(new TList),
   fOwner(tree),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Constructor.

   fEntryNext = fEntryMin + fgLearnEntries;
   Int_t nleaves = tree->GetListOfLeaves()->GetEntries();
   fBranches = new TBranch*[nleaves+10]; //add a margin just in case in a TChain?
}

//______________________________________________________________________________
TTreeCache::~TTreeCache()
{
   // destructor. (in general called by the TFile destructor

   delete [] fBranches;
   if (fBrNames) {fBrNames->Delete(); delete fBrNames; fBrNames=0;}
}

//_____________________________________________________________________________
void TTreeCache::AddBranch(TBranch *b)
{
   //add a branch to the list of branches to be stored in the cache
   //this function is called by TBranch::GetBasket

   if (!fIsLearning) return;

   // Reject branch that are not from the cached tree.
   if (!b || fTree != b->GetTree()) return;

   //Is branch already in the cache?
   Bool_t isNew = kTRUE;
   for (int i=0;i<fNbranches;i++) {
      if (fBranches[i] == b) {isNew = kFALSE; break;}
   }
   if (isNew) {
      // fTree = b->GetTree();
      fBranches[fNbranches] = b;
      fBrNames->Add(new TObjString(b->GetName()));
      fZipBytes += b->GetZipBytes();
      fNbranches++;
      if (gDebug > 0) printf("Entry: %lld, registering branch: %s\n",b->GetTree()->GetReadEntry(),b->GetName());
   }
}

//_____________________________________________________________________________
Bool_t TTreeCache::FillBuffer()
{
   // Fill the cache buffer with the branches in the cache.

   if (fNbranches <= 0) return kFALSE;
   TTree *tree = fBranches[0]->GetTree();
   Long64_t entry = tree->GetReadEntry();
   if (entry < fEntryNext) return kFALSE;

   // Estimate number of entries that can fit in the cache compare it
   // to the original value of fBufferSize not to the real one
   if (fZipBytes==0) {
      fEntryNext = entry + tree->GetEntries();;
   } else {
      fEntryNext = entry + tree->GetEntries()*fBufferSizeMin/fZipBytes;
   }
   if (fEntryMax <= 0) fEntryMax = tree->GetEntries();
   if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1;

   // Check if owner has a TEventList set. If yes we optimize for this
   // Special case reading only the baskets containing entries in the
   // list.
   TEventList *elist = fOwner->GetEventList();
   Long64_t chainOffset = 0;
   if (elist) {
      if (fOwner->IsA() ==TChain::Class()) {
         TChain *chain = (TChain*)fOwner;
         Int_t t = chain->GetTreeNumber();
         chainOffset = chain->GetTreeOffset()[t];
      }
   }

   //clear cache buffer
   TFileCacheRead::Prefetch(0,0);
   //store baskets
   Bool_t mustBreak = kFALSE;
   for (Int_t i=0;i<fNbranches;i++) {
      if (mustBreak) break;
      TBranch *b = fBranches[i];
      Int_t nb = b->GetMaxBaskets();
      Int_t *lbaskets   = b->GetBasketBytes();
      Long64_t *entries = b->GetBasketEntry();
      if (!lbaskets || !entries) continue;
      //we have found the branch. We now register all its baskets
      //from the requested offset to the basket below fEntrymax
      for (Int_t j=0;j<nb;j++) {
         Long64_t pos = b->GetBasketSeek(j);
         Int_t len = lbaskets[j];
         if (pos <= 0 || len <= 0) continue;
         if (entries[j] > fEntryNext) continue;
         if (entries[j] < entry && (j<nb-1 && entries[j+1] < entry)) continue;
         if (elist) {
            Long64_t emax = fEntryMax;
            if (j<nb-1) emax = entries[j+1]-1;
            if (!elist->ContainsRange(entries[j]+chainOffset,emax+chainOffset)) continue;
         }
         fNReadPref++;
         TFileCacheRead::Prefetch(pos,len);
         //we allow up to twice the default buffer size. When using eventlist in particular
         //it may happen that the evaluation of fEntryNext is bad, hence this protection
         if (fNtot > 2*fBufferSizeMin) {TFileCacheRead::Prefetch(0,0);mustBreak = kTRUE; break;}
      }
      if (gDebug > 0) printf("Entry: %lld, registering baskets branch %s, fEntryNext=%lld, fNseek=%d, fNtot=%d\n",entry,fBranches[i]->GetName(),fEntryNext,fNseek,fNtot);
   }
   fIsLearning = kFALSE;
   if (mustBreak) return kFALSE;
   return kTRUE;
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiency()
{
   // Give the total efficiency of the cache... defined as the ratio
   // of blocks found in the cache vs. the number of blocks prefetched
   // ( it could be more than 1 if we read the same block from the cache more
   //   than once )
   // Note: This should eb used at the end of the processing or we will
   //       get uncomplete stats

   if ( !fNReadPref )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)fNReadPref);
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiencyRel()
{
   // This will indicate a sort of relative efficiency... a ratio of the
   // reads found in the cache to the number of reads so far

   if ( !fNReadOk && !fNReadMiss )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)(fNReadOk + fNReadMiss));
}

//_____________________________________________________________________________
Int_t TTreeCache::GetLearnEntries()
{
   //static function returning the number of entries used to train the cache
   //see SetLearnEntries

   return fgLearnEntries;
}

//_____________________________________________________________________________
TTree *TTreeCache::GetTree() const
{
   //return Tree in the cache
   if (fNbranches <= 0) return 0;
   return fBranches[0]->GetTree();
}

//_____________________________________________________________________________
Int_t TTreeCache::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
   // Read buffer at position pos.
   // If pos is in the list of prefetched blocks read from fBuffer.
   // Otherwise try to fill the cache from the list of selected branches,
   // and recheck if pos is now in the list.
   // Returns
   //    -1 in case of read failure,
   //     0 in case not in cache,
   //     1 in case read from cache.
   // This function overloads TFileCacheRead::ReadBuffer.

   //Is request already in the cache?
   if (TFileCacheRead::ReadBuffer(buf,pos,len) == 1){
      fNReadOk++;
      return 1;
   }

   //not found in cache. Do we need to fill the cache?
   Bool_t bufferFilled = FillBuffer();
   if (bufferFilled) {
      Int_t res = TFileCacheRead::ReadBuffer(buf,pos,len);

      if (res == 1)
         fNReadOk++;
      else if (res == 0)
         fNReadMiss++;

      return res;
   }
   fNReadMiss++;

   return 0;
}

//_____________________________________________________________________________
void TTreeCache::SetEntryRange(Long64_t emin, Long64_t emax)
{
   // Set the minimum and maximum entry number to be processed
   // this information helps to optimize the number of baskets to read
   // when prefetching the branch buffers.

   fEntryMin  = emin;
   fEntryMax  = emax;
   fEntryNext  = fEntryMin + fgLearnEntries;
   if (gDebug > 0) printf("SetEntryRange: fEntryMin=%lld, fEntryMax=%lld, fEntryNext=%lld\n",fEntryMin,fEntryMax,fEntryNext);
   fIsLearning = kTRUE;
   fNbranches  = 0;
   fZipBytes   = 0;
   if (fBrNames) fBrNames->Delete();

}

//_____________________________________________________________________________
void TTreeCache::SetLearnEntries(Int_t n)
{
   // Static function to set the number of entries to be used in learning mode
   // The default value for n is 10. n must be >= 1

   if (n < 1) n = 1;
   fgLearnEntries = n;
}

//_____________________________________________________________________________
void TTreeCache::UpdateBranches(TTree *tree)
{
   //update pointer to current Tree and recompute pointers to the branches in the cache

   fTree = tree;

   fEntryMin  = 0;
   fEntryMax  = fTree->GetEntries();
   fEntryNext = fEntryMin + fgLearnEntries;
   fZipBytes  = 0;
   fNbranches = 0;
   TIter next(fBrNames);
   TObjString *os;
   while ((os = (TObjString*)next())) {
      TBranch *b = fTree->GetBranch(os->GetName());
      if (!b) continue;
      fBranches[fNbranches] = b;
      fZipBytes   += b->GetZipBytes();
      fNbranches++;
   }
}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: nadavs@google.com <Nadav Samet>

#ifndef RPCZ_SERVER_H
#define RPCZ_SERVER_H

#include "rpcz/macros.hpp"
#include "rpcz/rpcz.pb.h"

namespace zmq {
class socket_t;
};

namespace rpcz {
class application;
class client_connection;
class connection_manager;
class message_iterator;
class rpc_service;
class server_channel;
class service;

// A server object maps incoming RPC requests to a provided service interface.
// The service interface methods are executed inside a worker thread.
class server {
 public:
  // Constructs a server that uses the provided application. The
  // application must outlive the server.
  explicit server(application& application);

  // Constructs a server that uses the provided connection_manager. The
  // connection_manager must outlive the server.
  explicit server(connection_manager& connection_manager);

  ~server();

  // Registers an rpc service with this server. All registrations must occur
  // before bind() is called. The name parameter identifies the service for
  // external clients. If you use the first form, the service name from the
  // protocol buffer definition will be used. Does not take ownership of the
  // provided service.
  void register_service(service* service);
  void register_service(service* service, const std::string& name);

  void bind(const std::string& endpoint);

  // Registers a low-level rpc_service.
  void register_service(rpc_service* rpc_service, const std::string& name);

 private:
  void handle_request(const client_connection& connection,
                      message_iterator& iter);

  connection_manager& connection_manager_;
  typedef std::map<std::string, rpcz::rpc_service*> rpc_service_map;
  rpc_service_map service_map_;
  DISALLOW_COPY_AND_ASSIGN(server);
};

// rpc_service is a low-level request handler: requests and replies are void*.
// It is exposed here for language bindings. Do not use directly.
class rpc_service {
 public:
  virtual ~rpc_service() {}

  virtual void dispatch_request(const std::string& method,
                               const void* payload, size_t payload_len,
                               server_channel* channel_) = 0;
};
}  // namespace
#endif
<commit_msg>Fix documentation for register_service.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: nadavs@google.com <Nadav Samet>

#ifndef RPCZ_SERVER_H
#define RPCZ_SERVER_H

#include "rpcz/macros.hpp"
#include "rpcz/rpcz.pb.h"

namespace zmq {
class socket_t;
};

namespace rpcz {
class application;
class client_connection;
class connection_manager;
class message_iterator;
class rpc_service;
class server_channel;
class service;

// A server object maps incoming RPC requests to a provided service interface.
// The service interface methods are executed inside a worker thread.
class server {
 public:
  // Constructs a server that uses the provided application. The
  // application must outlive the server.
  explicit server(application& application);

  // Constructs a server that uses the provided connection_manager. The
  // connection_manager must outlive the server.
  explicit server(connection_manager& connection_manager);

  ~server();

  // Registers an rpc service with this server. All registrations must occur
  // before bind() is called. The name parameter identifies the service for
  // external clients. If you use the first form, the service name from the
  // protocol buffer definition will be used. Takes ownership of the
  // provided service.
  void register_service(service* service);
  void register_service(service* service, const std::string& name);

  void bind(const std::string& endpoint);

  // Registers a low-level rpc_service.
  void register_service(rpc_service* rpc_service, const std::string& name);

 private:
  void handle_request(const client_connection& connection,
                      message_iterator& iter);

  connection_manager& connection_manager_;
  typedef std::map<std::string, rpcz::rpc_service*> rpc_service_map;
  rpc_service_map service_map_;
  DISALLOW_COPY_AND_ASSIGN(server);
};

// rpc_service is a low-level request handler: requests and replies are void*.
// It is exposed here for language bindings. Do not use directly.
class rpc_service {
 public:
  virtual ~rpc_service() {}

  virtual void dispatch_request(const std::string& method,
                               const void* payload, size_t payload_len,
                               server_channel* channel_) = 0;
};
}  // namespace
#endif
<|endoftext|>


<commit_before>#include <node.h>
#include <nan.h>
#include <openssl/evp.h>
#include <openssl/ec.h>

#define CHECK(cond) do { if (!(cond)) goto error; } while (0)

using node::Buffer;
using v8::Handle;
using v8::FunctionTemplate;
using v8::Object;
using v8::String;

static const int PRIVKEY_SIZE = 32;
static const int PUBKEY_SIZE = 65;

int derive(const uint8_t* privkey_a, const uint8_t* pubkey_b, uint8_t* shared) {
  int rc = -1;
  int res;
  BIGNUM* pkey_bn = NULL;
  BIGNUM* peerkey_bn_x = NULL;
  BIGNUM* peerkey_bn_y = NULL;
  EC_KEY* pkey = NULL;
  EC_KEY* peerkey = NULL;
  EVP_PKEY* evp_pkey = NULL;
  EVP_PKEY* evp_peerkey = NULL;
  EVP_PKEY_CTX* ctx = NULL;
  size_t shared_len = PRIVKEY_SIZE;

  // Private key A.
  CHECK((pkey_bn = BN_bin2bn(privkey_a, PRIVKEY_SIZE, NULL)) != NULL);
  CHECK((pkey = EC_KEY_new_by_curve_name(NID_secp256k1)) != NULL);
  CHECK(EC_KEY_set_private_key(pkey, pkey_bn) == 1);
  CHECK((evp_pkey = EVP_PKEY_new()) != NULL);
  CHECK(EVP_PKEY_set1_EC_KEY(evp_pkey, pkey) == 1);

  // Public key B.
  CHECK((peerkey_bn_x = BN_bin2bn(pubkey_b+1, PRIVKEY_SIZE, NULL)) != NULL);
  CHECK((peerkey_bn_y = BN_bin2bn(pubkey_b+33, PRIVKEY_SIZE, NULL)) != NULL);
  CHECK((peerkey = EC_KEY_new_by_curve_name(NID_secp256k1)) != NULL);
  res = EC_KEY_set_public_key_affine_coordinates(peerkey,
                                                 peerkey_bn_x,
                                                 peerkey_bn_y);
  CHECK(res == 1);
  CHECK((evp_peerkey = EVP_PKEY_new()) != NULL);
  CHECK(EVP_PKEY_set1_EC_KEY(evp_peerkey, peerkey) == 1);

  // Derive shared secret.
  CHECK((ctx = EVP_PKEY_CTX_new(evp_pkey, NULL)) != NULL);
  CHECK(EVP_PKEY_derive_init(ctx) == 1);
  CHECK(EVP_PKEY_derive_set_peer(ctx, evp_peerkey) == 1);
  CHECK((EVP_PKEY_derive(ctx, shared, &shared_len)) == 1);
  CHECK(shared_len == PRIVKEY_SIZE);

  rc = 0;
error:
  EVP_PKEY_CTX_free(ctx);
  EVP_PKEY_free(evp_peerkey);
  EC_KEY_free(peerkey);
  BN_free(peerkey_bn_y);
  BN_free(peerkey_bn_x);
  EVP_PKEY_free(evp_pkey);
  EC_KEY_free(pkey);
  BN_free(pkey_bn);
  return rc;
}

NAN_METHOD(Derive) {
  NanScope();

  if (args.Length() != 2 ||
      !args[0]->IsObject() ||  // privkey_a
      !args[1]->IsObject()) {  // pubkey_b
    return NanThrowError("Bad input");
  }

  char* privkey_a = Buffer::Data(args[0]->ToObject());
  size_t privkey_a_len = Buffer::Length(args[0]->ToObject());
  char* pubkey_b = Buffer::Data(args[1]->ToObject());
  size_t pubkey_b_len = Buffer::Length(args[1]->ToObject());
  if (privkey_a == NULL ||
      privkey_a_len != PRIVKEY_SIZE ||
      pubkey_b == NULL ||
      pubkey_b_len != PUBKEY_SIZE ||
      pubkey_b[0] != 4) {
    return NanThrowError("Bad input");
  }

  uint8_t* shared = (uint8_t *)malloc(PRIVKEY_SIZE);
  if (shared == NULL ||
      derive((uint8_t *)privkey_a, (uint8_t *)pubkey_b, shared)) {
    free(shared);
    return NanThrowError("Internal error");
  }
  NanReturnValue(NanBufferUse((char *)shared, PRIVKEY_SIZE));
}

void InitAll(Handle<Object> exports) {
  exports->Set(
      NanNew<String>("derive"),
      NanNew<FunctionTemplate>(Derive)->GetFunction());
}

NODE_MODULE(ecdh, InitAll)
<commit_msg>Some final nits<commit_after>#include <node.h>
#include <nan.h>
#include <openssl/evp.h>
#include <openssl/ec.h>

using node::Buffer;
using v8::Handle;
using v8::FunctionTemplate;
using v8::Object;
using v8::String;

static const size_t PRIVKEY_SIZE = 32;
static const size_t PUBKEY_SIZE = 65;

#define CHECK(cond) do { if (!(cond)) goto error; } while (0)

int derive(const uint8_t* privkey_a, const uint8_t* pubkey_b, uint8_t* shared) {
  int rc = -1;
  int res;
  BIGNUM* pkey_bn = NULL;
  BIGNUM* peerkey_bn_x = NULL;
  BIGNUM* peerkey_bn_y = NULL;
  EC_KEY* pkey = NULL;
  EC_KEY* peerkey = NULL;
  EVP_PKEY* evp_pkey = NULL;
  EVP_PKEY* evp_peerkey = NULL;
  EVP_PKEY_CTX* ctx = NULL;
  size_t shared_len = PRIVKEY_SIZE;

  // Private key A.
  CHECK((pkey_bn = BN_bin2bn(privkey_a, PRIVKEY_SIZE, NULL)) != NULL);
  CHECK((pkey = EC_KEY_new_by_curve_name(NID_secp256k1)) != NULL);
  CHECK(EC_KEY_set_private_key(pkey, pkey_bn) == 1);
  CHECK((evp_pkey = EVP_PKEY_new()) != NULL);
  CHECK(EVP_PKEY_set1_EC_KEY(evp_pkey, pkey) == 1);

  // Public key B.
  CHECK((peerkey_bn_x = BN_bin2bn(pubkey_b+1, PRIVKEY_SIZE, NULL)) != NULL);
  CHECK((peerkey_bn_y = BN_bin2bn(pubkey_b+33, PRIVKEY_SIZE, NULL)) != NULL);
  CHECK((peerkey = EC_KEY_new_by_curve_name(NID_secp256k1)) != NULL);
  res = EC_KEY_set_public_key_affine_coordinates(peerkey,
                                                 peerkey_bn_x,
                                                 peerkey_bn_y);
  CHECK(res == 1);
  CHECK((evp_peerkey = EVP_PKEY_new()) != NULL);
  CHECK(EVP_PKEY_set1_EC_KEY(evp_peerkey, peerkey) == 1);

  // Derive shared secret.
  CHECK((ctx = EVP_PKEY_CTX_new(evp_pkey, NULL)) != NULL);
  CHECK(EVP_PKEY_derive_init(ctx) == 1);
  CHECK(EVP_PKEY_derive_set_peer(ctx, evp_peerkey) == 1);
  CHECK((EVP_PKEY_derive(ctx, shared, &shared_len)) == 1);
  CHECK(shared_len == PRIVKEY_SIZE);

  rc = 0;
error:
  EVP_PKEY_CTX_free(ctx);
  EVP_PKEY_free(evp_peerkey);
  EC_KEY_free(peerkey);
  BN_free(peerkey_bn_y);
  BN_free(peerkey_bn_x);
  EVP_PKEY_free(evp_pkey);
  EC_KEY_free(pkey);
  BN_free(pkey_bn);
  return rc;
}

#undef CHECK

NAN_METHOD(Derive) {
  NanScope();

  if (args.Length() != 2 ||
      !args[0]->IsObject() ||  // privkey_a
      !args[1]->IsObject()) {  // pubkey_b
    return NanThrowError("Bad input");
  }

  char* privkey_a = Buffer::Data(args[0]->ToObject());
  size_t privkey_a_len = Buffer::Length(args[0]->ToObject());
  char* pubkey_b = Buffer::Data(args[1]->ToObject());
  size_t pubkey_b_len = Buffer::Length(args[1]->ToObject());
  if (privkey_a == NULL ||
      privkey_a_len != PRIVKEY_SIZE ||
      pubkey_b == NULL ||
      pubkey_b_len != PUBKEY_SIZE ||
      pubkey_b[0] != 4) {
    return NanThrowError("Bad input");
  }

  uint8_t* shared = (uint8_t *)malloc(PRIVKEY_SIZE);
  if (shared == NULL ||
      derive((uint8_t *)privkey_a, (uint8_t *)pubkey_b, shared)) {
    free(shared);
    return NanThrowError("Internal error");
  }
  NanReturnValue(NanBufferUse((char *)shared, PRIVKEY_SIZE));
}

void InitAll(Handle<Object> exports) {
  exports->Set(
      NanNew<String>("derive"),
      NanNew<FunctionTemplate>(Derive)->GetFunction());
}

NODE_MODULE(ecdh, InitAll)
<|endoftext|>


<commit_before>#pragma once

#include "plugin_base.hpp"
#include "../../../../base/string_utils.hpp"
#include "../../../../coding/file_container.hpp"
#include "../../../../coding/read_write_utils.hpp"
#include "../../../../defines.hpp"
#include "../../../../geometry/region2d.hpp"
#include "../../../../indexer/geometry_serialization.hpp"
#include "../../../../geometry/mercator.hpp"
#include "../../../../storage/country_decl.hpp"
#include "../../../../storage/country_polygon.hpp"

#include "../algorithms/object_encoder.hpp"
#include "../data_structures/search_engine.hpp"
#include "../data_structures/edge_based_node_data.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../descriptors/gpx_descriptor.hpp"
#include "../descriptors/json_descriptor.hpp"
#include "../util/integer_range.hpp"
#include "../util/json_renderer.hpp"
#include "../util/make_unique.hpp"
#include "../util/simple_logger.hpp"

#include <algorithm>
#include <limits>
#include <memory>
#include <unordered_map>
#include <string>
#include <vector>

template <class DataFacadeT> class MapsMePlugin final : public BasePlugin
{
    class GetByPoint
    {
        m2::PointD const &m_pt;
        std::vector<std::vector<m2::RegionD>> const &m_regions;

      public:
        size_t m_res;

        GetByPoint(std::vector<std::vector<m2::RegionD>> const &regions, m2::PointD const &pt)
            : m_pt(pt), m_regions(regions), m_res(-1)
        {
        }

        /// @param[in] id Index in m_countries.
        /// @return false If point is in country.
        bool operator()(size_t id)
        {
            auto it =
                find_if(m_regions[id].begin(), m_regions[id].end(), [&](m2::RegionD const &region)
                        { return region.Contains(m_pt);});
            if (it == m_regions[id].end())
                    return true;
            m_res = id;
            return false;
        }
    };

public:
    explicit MapsMePlugin(DataFacadeT *facade, std::string const &baseDir, std::string const & nodeDataFile)
        : m_descriptorString("mapsme"), m_facade(facade),
          m_reader(baseDir + '/' + PACKED_POLYGONS_FILE)
    {
#ifndef MT_STRUCTURES
        SimpleLogger().Write(logWARNING) << "Multitreaded storage was not set on compile time!!! Do not use osrm-routed in several threads."
#endif
        if (!osrm::LoadNodeDataFromFile(nodeDataFile, m_nodeData))
        {
          SimpleLogger().Write(logDEBUG) << "Can't load node data";
          return;
        }
        ReaderSource<ModelReaderPtr> src(m_reader.GetReader(PACKED_POLYGONS_INFO_TAG));
        rw::Read(src, m_countries);
        m_regions.resize(m_countries.size());
        for (size_t i = 0; i < m_countries.size(); ++i)
        {
            // load regions from file
            ReaderSource<ModelReaderPtr> src(m_reader.GetReader(strings::to_string(i)));

            uint32_t const count = ReadVarUint<uint32_t>(src);
            for (size_t j = 0; j < count; ++j)
            {
                vector<m2::PointD> points;
                serial::LoadOuterPath(src, serial::CodingParams(), points);

                m_regions[i].emplace_back(move(m2::RegionD(points.begin(), points.end())));
            }
        }
        m_searchEngine = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
    }

    template <class ToDo> void ForEachCountry(m2::PointD const &pt, ToDo &toDo) const
    {
        for (size_t i = 0; i < m_countries.size(); ++i)
            if (m_countries[i].m_rect.IsPointInside(pt))
                if (!toDo(i))
                    return;
    }

    virtual ~MapsMePlugin() {}

    const std::string GetDescriptor() const override final { return m_descriptorString; }

    int HandleRequest(const RouteParameters &route_parameters, osrm::json::Object &reply) override final
    {
        //We process only two points case
        if (route_parameters.coordinates.size() != 2)
            return 400;

        if (!check_all_coordinates(route_parameters.coordinates))
        {
            return 400;
        }

        std::vector<phantom_node_pair> phantom_node_pair_list(route_parameters.coordinates.size());

        for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
        {
            std::vector<PhantomNode> phantom_node_vector;
            //FixedPointCoordinate &coordinate = route_parameters.coordinates[i];
            if (m_facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
                                                                phantom_node_vector, 1))
            {
                BOOST_ASSERT(!phantom_node_vector.empty());
                phantom_node_pair_list[i].first = phantom_node_vector.front();
                if (phantom_node_vector.size() > 1)
                {
                    phantom_node_pair_list[i].second = phantom_node_vector.back();
                }
            }
        }

        auto check_component_id_is_tiny = [](const phantom_node_pair &phantom_pair)
        {
            return phantom_pair.first.component_id != 0;
        };

        const bool every_phantom_is_in_tiny_cc =
                std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
                            check_component_id_is_tiny);

        // are all phantoms from a tiny cc?
        const auto component_id = phantom_node_pair_list.front().first.component_id;

        auto check_component_id_is_equal = [component_id](const phantom_node_pair &phantom_pair)
        {
            return component_id == phantom_pair.first.component_id;
        };

        const bool every_phantom_has_equal_id =
                std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
                            check_component_id_is_equal);

        auto swap_phantom_from_big_cc_into_front = [](phantom_node_pair &phantom_pair)
        {
            if (0 != phantom_pair.first.component_id)
            {
                using namespace std;
                swap(phantom_pair.first, phantom_pair.second);
            }
        };

        // this case is true if we take phantoms from the big CC
        if (!every_phantom_is_in_tiny_cc || !every_phantom_has_equal_id)
        {
            std::for_each(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
                          swap_phantom_from_big_cc_into_front);
        }

        InternalRouteResult raw_route;
        auto build_phantom_pairs =
           [&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair)
        {
            raw_route.segment_end_coordinates.emplace_back(
                PhantomNodes{first_pair.first, second_pair.first});
        };

        osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);

        vector<bool> uturns;
        m_searchEngine->shortest_path(raw_route.segment_end_coordinates, uturns, raw_route);
        if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
        {
            SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
            return 400;
        }
        // Get mwm names
        vector<pair<string, m2::PointD>> usedMwms;

        for (auto i : osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
        {
            size_t const n = raw_route.unpacked_path_segments[i].size();
            for (size_t j = 0; j < n; ++j)
            {
                PathData const &path_data = raw_route.unpacked_path_segments[i][j];
                auto const & data = m_nodeData[path_data.node];
                if (data.m_segments.empty())
                    continue;
                auto const & seg = data.m_segments.front();
                m2::PointD pt = MercatorBounds::FromLatLon(seg.lat1, seg.lon1);
                GetByPoint doGet(m_regions, pt);
                ForEachCountry(pt, doGet);

                if (doGet.m_res != std::numeric_limits<size_t>::max())
                    usedMwms.emplace_back(make_pair(m_countries[doGet.m_res].m_name, pt));
            }
        }

        auto const it = std::unique(usedMwms.begin(), usedMwms.end(), [&]
                                    (pair<string, m2::PointD> const & a, pair<string, m2::PointD> const & b)
                                    {
                                        return a.first == b.first;
                                    });
        usedMwms.erase(it, usedMwms.end());

        osrm::json::Array json_array;
        for (auto & mwm : usedMwms)
        {
            osrm::json::Array pointArray;
            pointArray.values.push_back(mwm.second.x);
            pointArray.values.push_back(mwm.second.y);
            pointArray.values.push_back(mwm.first);
            json_array.values.push_back(pointArray);
        }
        reply.values["used_mwms"] = json_array;

        return 200;
    }

  private:
    std::unique_ptr<SearchEngine<DataFacadeT>> m_searchEngine;
    std::vector<storage::CountryDef> m_countries;
    std::vector<std::vector<m2::RegionD>> m_regions;
    std::string m_descriptorString;
    DataFacadeT * m_facade;
    FilesContainerR m_reader;
    osrm::NodeDataVectorT m_nodeData;
};
<commit_msg>OSRM mapsme plugin small mwm fix.<commit_after>#pragma once

#include "plugin_base.hpp"
#include "../../../../base/string_utils.hpp"
#include "../../../../coding/file_container.hpp"
#include "../../../../coding/read_write_utils.hpp"
#include "../../../../defines.hpp"
#include "../../../../geometry/region2d.hpp"
#include "../../../../indexer/geometry_serialization.hpp"
#include "../../../../geometry/mercator.hpp"
#include "../../../../storage/country_decl.hpp"
#include "../../../../storage/country_polygon.hpp"

#include "../algorithms/object_encoder.hpp"
#include "../data_structures/search_engine.hpp"
#include "../data_structures/edge_based_node_data.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../descriptors/gpx_descriptor.hpp"
#include "../descriptors/json_descriptor.hpp"
#include "../util/integer_range.hpp"
#include "../util/json_renderer.hpp"
#include "../util/make_unique.hpp"
#include "../util/simple_logger.hpp"

#include <algorithm>
#include <limits>
#include <memory>
#include <unordered_map>
#include <string>
#include <vector>

template <class DataFacadeT> class MapsMePlugin final : public BasePlugin
{
    class GetByPoint
    {
        m2::PointD const &m_pt;
        std::vector<std::vector<m2::RegionD>> const &m_regions;

      public:
        size_t m_res;

        GetByPoint(std::vector<std::vector<m2::RegionD>> const &regions, m2::PointD const &pt)
            : m_pt(pt), m_regions(regions), m_res(-1)
        {
        }

        /// @param[in] id Index in m_countries.
        /// @return false If point is in country.
        bool operator()(size_t id)
        {
            auto it =
                find_if(m_regions[id].begin(), m_regions[id].end(), [&](m2::RegionD const &region)
                        { return region.Contains(m_pt);});
            if (it == m_regions[id].end())
                    return true;
            m_res = id;
            return false;
        }
    };

public:
    explicit MapsMePlugin(DataFacadeT *facade, std::string const &baseDir, std::string const & nodeDataFile)
        : m_descriptorString("mapsme"), m_facade(facade),
          m_reader(baseDir + '/' + PACKED_POLYGONS_FILE)
    {
#ifndef MT_STRUCTURES
        SimpleLogger().Write(logWARNING) << "Multitreaded storage was not set on compile time!!! Do not use osrm-routed in several threads."
#endif
        if (!osrm::LoadNodeDataFromFile(nodeDataFile, m_nodeData))
        {
          SimpleLogger().Write(logDEBUG) << "Can't load node data";
          return;
        }
        ReaderSource<ModelReaderPtr> src(m_reader.GetReader(PACKED_POLYGONS_INFO_TAG));
        rw::Read(src, m_countries);
        m_regions.resize(m_countries.size());
        for (size_t i = 0; i < m_countries.size(); ++i)
        {
            // load regions from file
            ReaderSource<ModelReaderPtr> src(m_reader.GetReader(strings::to_string(i)));

            uint32_t const count = ReadVarUint<uint32_t>(src);
            for (size_t j = 0; j < count; ++j)
            {
                vector<m2::PointD> points;
                serial::LoadOuterPath(src, serial::CodingParams(), points);

                m_regions[i].emplace_back(move(m2::RegionD(points.begin(), points.end())));
            }
        }
        m_searchEngine = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
    }

    template <class ToDo> void ForEachCountry(m2::PointD const &pt, ToDo &toDo) const
    {
        for (size_t i = 0; i < m_countries.size(); ++i)
            if (m_countries[i].m_rect.IsPointInside(pt))
                if (!toDo(i))
                    return;
    }

    virtual ~MapsMePlugin() {}

    const std::string GetDescriptor() const override final { return m_descriptorString; }

    int HandleRequest(const RouteParameters &route_parameters, osrm::json::Object &reply) override final
    {
        //We process only two points case
        if (route_parameters.coordinates.size() != 2)
            return 400;

        if (!check_all_coordinates(route_parameters.coordinates))
        {
            return 400;
        }

        std::vector<phantom_node_pair> phantom_node_pair_list(route_parameters.coordinates.size());

        for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
        {
            std::vector<PhantomNode> phantom_node_vector;
            //FixedPointCoordinate &coordinate = route_parameters.coordinates[i];
            if (m_facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
                                                                phantom_node_vector, 1))
            {
                BOOST_ASSERT(!phantom_node_vector.empty());
                phantom_node_pair_list[i].first = phantom_node_vector.front();
                if (phantom_node_vector.size() > 1)
                {
                    phantom_node_pair_list[i].second = phantom_node_vector.back();
                }
            }
        }

        auto check_component_id_is_tiny = [](const phantom_node_pair &phantom_pair)
        {
            return phantom_pair.first.component_id != 0;
        };

        const bool every_phantom_is_in_tiny_cc =
                std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
                            check_component_id_is_tiny);

        // are all phantoms from a tiny cc?
        const auto component_id = phantom_node_pair_list.front().first.component_id;

        auto check_component_id_is_equal = [component_id](const phantom_node_pair &phantom_pair)
        {
            return component_id == phantom_pair.first.component_id;
        };

        const bool every_phantom_has_equal_id =
                std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
                            check_component_id_is_equal);

        auto swap_phantom_from_big_cc_into_front = [](phantom_node_pair &phantom_pair)
        {
            if (0 != phantom_pair.first.component_id)
            {
                using namespace std;
                swap(phantom_pair.first, phantom_pair.second);
            }
        };

        // this case is true if we take phantoms from the big CC
        if (!every_phantom_is_in_tiny_cc || !every_phantom_has_equal_id)
        {
            std::for_each(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
                          swap_phantom_from_big_cc_into_front);
        }

        InternalRouteResult raw_route;
        auto build_phantom_pairs =
           [&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair)
        {
            raw_route.segment_end_coordinates.emplace_back(
                PhantomNodes{first_pair.first, second_pair.first});
        };

        osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);

        vector<bool> uturns;
        m_searchEngine->shortest_path(raw_route.segment_end_coordinates, uturns, raw_route);
        if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
        {
            SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
            return 400;
        }
        // Get mwm names
        vector<pair<size_t, m2::PointD>> usedMwms;
        size_t lastUsedMwm = numeric_limits<size_t>::max();
        vector<m2::PointD> mwmPoints;

        for (auto i : osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
        {
            size_t const n = raw_route.unpacked_path_segments[i].size();
            for (size_t j = 0; j < n; ++j)
            {
                PathData const &path_data = raw_route.unpacked_path_segments[i][j];
                auto const & data = m_nodeData[path_data.node];
                if (data.m_segments.empty())
                    continue;
                auto const & seg = data.m_segments.front();
                m2::PointD pt = MercatorBounds::FromLatLon(seg.lat1, seg.lon1);
                GetByPoint doGet(m_regions, pt);
                ForEachCountry(pt, doGet);

                auto const & index = doGet.m_res;
                if (index == std::numeric_limits<size_t>::max())
                  continue;

                if (index != lastUsedMwm)
                {
                  if (!mwmPoints.empty())
                  {
                    // Get the middlest point (max far from borders).
                    size_t delta = std::distance(mwmPoints.begin(), mwmPoints.end()) / 2;
                    usedMwms.emplace_back(lastUsedMwm, mwmPoints[delta]);
                    mwmPoints.clear();
                  }
                  lastUsedMwm = index;
                }
                mwmPoints.push_back(pt);
            }
        }
        // Get point from last mwm.
        if (!mwmPoints.empty())
        {
          size_t delta = std::distance(mwmPoints.begin(), mwmPoints.end()) / 2;
          usedMwms.emplace_back(lastUsedMwm, mwmPoints[delta]);
          mwmPoints.clear();
        }

        std::sort(usedMwms.begin(), usedMwms.end(), []
                  (pair<size_t, m2::PointD> const & a, pair<size_t, m2::PointD> const & b)
                  {
                    return a.first < b.first;
                  });
        auto const it = std::unique(usedMwms.begin(), usedMwms.end(), []
                                    (pair<size_t, m2::PointD> const & a, pair<size_t, m2::PointD> const & b)
                                    {
                                        return a.first == b.first;
                                    });
        usedMwms.erase(it, usedMwms.end());

        osrm::json::Array json_array;
        for (auto & mwm : usedMwms)
        {
            osrm::json::Array pointArray;
            pointArray.values.push_back(mwm.second.x);
            pointArray.values.push_back(mwm.second.y);
            pointArray.values.push_back(m_countries[mwm.first].m_name);
            json_array.values.push_back(pointArray);
        }
        reply.values["used_mwms"] = json_array;

        return 200;
    }

  private:
    std::unique_ptr<SearchEngine<DataFacadeT>> m_searchEngine;
    std::vector<storage::CountryDef> m_countries;
    std::vector<std::vector<m2::RegionD>> m_regions;
    std::string m_descriptorString;
    DataFacadeT * m_facade;
    FilesContainerR m_reader;
    osrm::NodeDataVectorT m_nodeData;
};
<|endoftext|>