<commit_before>/*
   Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING. If not, write to the
   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
   MA  02110-1301  USA.
*/

/* yaSSL buffer header implements input/output buffers to simulate streaming
 * with SSL types and sockets
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>             // memcpy
#include "runtime.hpp"
#include "buffer.hpp"
#include "yassl_types.hpp"

namespace yaSSL {

/* return 0 on check success, always true for NoCheck policy */
int NoCheck::check(uint, uint)
{
    return 0;
}

/* return 0 on check success */
int Check::check(uint i, uint max)
{
    if (i < max)
        return 0;

    return -1;
}

/* input_buffer operates like a smart c style array with a checking option,
 * meant to be read from through [] with AUTO index or read().
 * Should only write to at/near construction with assign() or raw (e.g., recv)
 * followed by add_size with the number of elements added by raw write.
 *
 * Not using vector because need checked []access, offset, and the ability to
 * write to the buffer bulk wise and have the correct size
 */

input_buffer::input_buffer()
    : size_(0), current_(0), buffer_(0), end_(0), error_(0), zero_(0)
{}

input_buffer::input_buffer(uint s)
    : size_(0), current_(0), buffer_(NEW_YS byte[s]), end_(buffer_ + s),
      error_(0), zero_(0)
{}

// with assign
input_buffer::input_buffer(uint s, const byte* t, uint len)
    : size_(0), current_(0), buffer_(NEW_YS byte[s]), end_(buffer_ + s),
      error_(0), zero_(0)
{
    assign(t, len);
}

input_buffer::~input_buffer()
{
    ysArrayDelete(buffer_);
}

// users can pass defualt zero length buffer and then allocate
void input_buffer::allocate(uint s)
{
    if (error_ == 0) {
        buffer_ = NEW_YS byte[s];
        end_ = buffer_ + s;
    }
}

// for passing to raw writing functions at beginning, then use add_size
byte* input_buffer::get_buffer() const
{
    return buffer_;
}

// after a raw write user can set NEW_YS size
// if you know the size before the write use assign()
void input_buffer::add_size(uint i)
{
    if (error_ == 0 && check(size_ + i-1, get_capacity()) == 0)
        size_ += i;
    else
        error_ = -1;
}

uint input_buffer::get_capacity()  const
{
    if (error_ == 0)
        return end_ - buffer_;

    return 0;
}

uint input_buffer::get_current()   const
{
    if (error_ == 0)
        return current_;

    return 0;
}

uint input_buffer::get_size()      const
{
    if (error_ == 0)
        return size_;

    return 0;
}

uint input_buffer::get_remaining() const
{
    if (error_ == 0)
        return size_ - current_;

    return 0;
}

int input_buffer::get_error() const
{
    return error_;
}

void input_buffer::set_error()
{
    error_ = -1;
}

void input_buffer::set_current(uint i)
{
    if (error_ == 0 && i && check(i - 1, size_) == 0)
        current_ = i;
    else
        error_ = -1;
}

// read only access through [], advance current
// user passes in AUTO index for ease of use
const byte& input_buffer::operator[](uint i)
{
    if (error_ == 0 && check(current_, size_) == 0)
        return buffer_[current_++];

    error_ = -1;
    return zero_;
}

// end of input test
bool input_buffer::eof()
{
    if (error_ != 0)
        return true;

    return current_ >= size_;
}

// peek ahead
byte input_buffer::peek()
{
    if (error_ == 0 && check(current_, size_) == 0)
        return buffer_[current_];

    error_ = -1;
    return 0;
}

// write function, should use at/near construction
void input_buffer::assign(const byte* t, uint s)
{
    if (t && error_ == 0 && check(current_, get_capacity()) == 0) {
        add_size(s);
        if (error_ == 0) {
            memcpy(&buffer_[current_], t, s);
            return;  // success
        }
    }

    error_ = -1;
}

// use read to query input, adjusts current
void input_buffer::read(byte* dst, uint length)
{
    if (dst && error_ == 0 && check(current_ + length - 1, size_) == 0) {
        memcpy(dst, &buffer_[current_], length);
        current_ += length;
    } else {
        error_ = -1;
    }
}

/* output_buffer operates like a smart c style array with a checking option.
 * Meant to be written to through [] with AUTO index or write().
 * Size (current) counter increases when written to. Can be constructed with
 * zero length buffer but be sure to allocate before first use.
 * Don't use add write for a couple bytes, use [] instead, way less overhead.
 *
 * Not using vector because need checked []access and the ability to
 * write to the buffer bulk wise and retain correct size
 */

output_buffer::output_buffer()
    : current_(0), buffer_(0), end_(0)
{}

// with allocate
output_buffer::output_buffer(uint s)
    : current_(0), buffer_(NEW_YS byte[s]), end_(buffer_ + s)
{}

// with assign
output_buffer::output_buffer(uint s, const byte* t, uint len)
    : current_(0), buffer_(NEW_YS byte[s]), end_(buffer_+ s)
{
    write(t, len);
}

output_buffer::~output_buffer()
{
    ysArrayDelete(buffer_);
}

uint output_buffer::get_size() const
{
    return current_;
}

uint output_buffer::get_capacity() const
{
    return (uint) (end_ - buffer_);
}

void output_buffer::set_current(uint c)
{
    check(c, get_capacity());
    current_ = c;
}

// users can pass defualt zero length buffer and then allocate
void output_buffer::allocate(uint s)
{
    buffer_ = NEW_YS byte[s]; end_ = buffer_ + s;
}

// for passing to reading functions when finished
const byte* output_buffer::get_buffer() const
{
    return buffer_;
}

// allow write access through [], update current
// user passes in AUTO as index for ease of use
byte& output_buffer::operator[](uint i)
{
    check(current_, get_capacity());
    return buffer_[current_++];
}

// end of output test
bool output_buffer::eof()
{
    return current_ >= get_capacity();
}

void output_buffer::write(const byte* t, uint s)
{
    check(current_ + s - 1, get_capacity());
    memcpy(&buffer_[current_], t, s);
    current_ += s;
}

} // naemspace

<commit_msg>Fix YaSSL on windows<commit_after>/*
   Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING. If not, write to the
   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
   MA  02110-1301  USA.
*/

/* yaSSL buffer header implements input/output buffers to simulate streaming
 * with SSL types and sockets
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>             // memcpy
#include "runtime.hpp"
#include "buffer.hpp"
#include "yassl_types.hpp"

namespace yaSSL {

/* return 0 on check success, always true for NoCheck policy */
int NoCheck::check(uint, uint)
{
    return 0;
}

/* return 0 on check success */
int Check::check(uint i, uint max)
{
    if (i < max)
        return 0;

    return -1;
}

/* input_buffer operates like a smart c style array with a checking option,
 * meant to be read from through [] with AUTO index or read().
 * Should only write to at/near construction with assign() or raw (e.g., recv)
 * followed by add_size with the number of elements added by raw write.
 *
 * Not using vector because need checked []access, offset, and the ability to
 * write to the buffer bulk wise and have the correct size
 */

input_buffer::input_buffer()
    : size_(0), current_(0), buffer_(0), end_(0), error_(0), zero_(0)
{}

input_buffer::input_buffer(uint s)
    : size_(0), current_(0), buffer_(NEW_YS byte[s]), end_(buffer_ + s),
      error_(0), zero_(0)
{}

// with assign
input_buffer::input_buffer(uint s, const byte* t, uint len)
    : size_(0), current_(0), buffer_(NEW_YS byte[s]), end_(buffer_ + s),
      error_(0), zero_(0)
{
    assign(t, len);
}

input_buffer::~input_buffer()
{
    ysArrayDelete(buffer_);
}

// users can pass defualt zero length buffer and then allocate
void input_buffer::allocate(uint s)
{
    if (error_ == 0) {
        buffer_ = NEW_YS byte[s];
        end_ = buffer_ + s;
    }
}

// for passing to raw writing functions at beginning, then use add_size
byte* input_buffer::get_buffer() const
{
    return buffer_;
}

// after a raw write user can set NEW_YS size
// if you know the size before the write use assign()
void input_buffer::add_size(uint i)
{
    if (error_ == 0 && check(size_ + i-1, get_capacity()) == 0)
        size_ += i;
    else
        error_ = -1;
}

uint input_buffer::get_capacity()  const
{
    if (error_ == 0)
        return end_ - buffer_;

    return 0;
}

uint input_buffer::get_current()   const
{
    if (error_ == 0)
        return current_;

    return 0;
}

uint input_buffer::get_size()      const
{
    if (error_ == 0)
        return size_;

    return 0;
}

uint input_buffer::get_remaining() const
{
    if (error_ == 0)
        return size_ - current_;

    return 0;
}

int input_buffer::get_error() const
{
    return error_;
}

void input_buffer::set_error()
{
    error_ = -1;
}

void input_buffer::set_current(uint i)
{
    if (error_ == 0 && (i == 0 || check(i - 1, size_) == 0))
        current_ = i;
    else
        error_ = -1;
}

// read only access through [], advance current
// user passes in AUTO index for ease of use
const byte& input_buffer::operator[](uint i)
{
    if (error_ == 0 && check(current_, size_) == 0)
        return buffer_[current_++];

    error_ = -1;
    return zero_;
}

// end of input test
bool input_buffer::eof()
{
    if (error_ != 0)
        return true;

    return current_ >= size_;
}

// peek ahead
byte input_buffer::peek()
{
    if (error_ == 0 && check(current_, size_) == 0)
        return buffer_[current_];

    error_ = -1;
    return 0;
}

// write function, should use at/near construction
void input_buffer::assign(const byte* t, uint s)
{
    if (t && error_ == 0 && check(current_, get_capacity()) == 0) {
        add_size(s);
        if (error_ == 0) {
            memcpy(&buffer_[current_], t, s);
            return;  // success
        }
    }

    error_ = -1;
}

// use read to query input, adjusts current
void input_buffer::read(byte* dst, uint length)
{
    if (dst && error_ == 0 && check(current_ + length - 1, size_) == 0) {
        memcpy(dst, &buffer_[current_], length);
        current_ += length;
    } else {
        error_ = -1;
    }
}

/* output_buffer operates like a smart c style array with a checking option.
 * Meant to be written to through [] with AUTO index or write().
 * Size (current) counter increases when written to. Can be constructed with
 * zero length buffer but be sure to allocate before first use.
 * Don't use add write for a couple bytes, use [] instead, way less overhead.
 *
 * Not using vector because need checked []access and the ability to
 * write to the buffer bulk wise and retain correct size
 */

output_buffer::output_buffer()
    : current_(0), buffer_(0), end_(0)
{}

// with allocate
output_buffer::output_buffer(uint s)
    : current_(0), buffer_(NEW_YS byte[s]), end_(buffer_ + s)
{}

// with assign
output_buffer::output_buffer(uint s, const byte* t, uint len)
    : current_(0), buffer_(NEW_YS byte[s]), end_(buffer_+ s)
{
    write(t, len);
}

output_buffer::~output_buffer()
{
    ysArrayDelete(buffer_);
}

uint output_buffer::get_size() const
{
    return current_;
}

uint output_buffer::get_capacity() const
{
    return (uint) (end_ - buffer_);
}

void output_buffer::set_current(uint c)
{
    check(c, get_capacity());
    current_ = c;
}

// users can pass defualt zero length buffer and then allocate
void output_buffer::allocate(uint s)
{
    buffer_ = NEW_YS byte[s]; end_ = buffer_ + s;
}

// for passing to reading functions when finished
const byte* output_buffer::get_buffer() const
{
    return buffer_;
}

// allow write access through [], update current
// user passes in AUTO as index for ease of use
byte& output_buffer::operator[](uint i)
{
    check(current_, get_capacity());
    return buffer_[current_++];
}

// end of output test
bool output_buffer::eof()
{
    return current_ >= get_capacity();
}

void output_buffer::write(const byte* t, uint s)
{
    check(current_ + s - 1, get_capacity());
    memcpy(&buffer_[current_], t, s);
    current_ += s;
}

} // naemspace

<|endoftext|>


<commit_before>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "RoutingInputWidget.h"

#include "MarbleDebug.h"
#include "MarbleLocale.h"
#include "MarblePlacemarkModel.h"
#include "MarbleRunnerManager.h"
#include "RouteSkeleton.h"
#include "TinyWebBrowser.h"

#include <QtCore/QTimer>
#include <QtCore/QUrl>
#include <QtGui/QHBoxLayout>
#include <QtGui/QIcon>
#include <QtGui/QLineEdit>
#include <QtGui/QPushButton>
#include <QtGui/QMovie>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtXml/QDomDocument>

namespace Marble
{

class RoutingInputWidgetPrivate
{
public:
    QPushButton *m_stateButton;

    QLineEdit *m_lineEdit;

    QPushButton *m_removeButton;

    QPushButton *m_pickButton;

    MarbleRunnerManager *m_runnerManager;

    MarblePlacemarkModel *m_placemarkModel;

    QMovie m_progress;

    QTimer m_progressTimer;

    RouteSkeleton *m_route;

    int m_index;

    QNetworkAccessManager *m_manager;

    QTimer m_nominatimTimer;

    bool m_workOffline;

    /** Constructor */
    RoutingInputWidgetPrivate( RouteSkeleton *skeleton, int index, PluginManager* manager, QWidget *parent );

    /** Initiate reverse geocoding request to download address */
    void adjustText();
};

RoutingInputWidgetPrivate::RoutingInputWidgetPrivate( RouteSkeleton *skeleton, int index, PluginManager* manager, QWidget *parent ) :
        m_lineEdit( 0 ), m_runnerManager( new MarbleRunnerManager( manager, parent ) ),
        m_placemarkModel( 0 ), m_progress( ":/data/bitmaps/progress.mng" ),
        m_route( skeleton ), m_index( index ), m_manager( new QNetworkAccessManager( parent ) ),
        m_workOffline( false )
{
    m_stateButton = new QPushButton( parent );
    m_stateButton->setToolTip( "Center Map here" );
    m_stateButton->setVisible( false );
    m_stateButton->setIcon( QIcon( m_route->pixmap( m_index ) ) );
    m_stateButton->setFlat( true );
    m_stateButton->setMaximumWidth( 22 );
    m_stateButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );

    m_lineEdit = new QLineEdit( parent );

    m_removeButton = new QPushButton( parent );
    m_removeButton->setIcon( QIcon( ":/data/bitmaps/routing_remove.png" ) );
    m_removeButton->setToolTip( "Remove this position" );
    m_removeButton->setFlat( true );
    m_removeButton->setMaximumWidth( 22 );

    m_pickButton = new QPushButton( parent );
    m_pickButton->setIcon( QIcon( m_route->pixmap( m_index ) ) );
    m_pickButton->setToolTip( "Choose position from the map" );
    m_pickButton->setCheckable( true );
    m_pickButton->setFlat( true );
    m_pickButton->setMaximumWidth( 22 );
    m_pickButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );

    m_progressTimer.setInterval( 100 );
    m_nominatimTimer.setInterval( 1000 );
    m_nominatimTimer.setSingleShot( true );

    GeoDataCoordinates pos = m_route->at( m_index );
    if ( pos.longitude() != 0.0 && pos.latitude() != 0.0 ) {
        m_lineEdit->setText( pos.toString() );
        m_pickButton->setVisible( false );
        m_stateButton->setVisible( true );
    }
}

void RoutingInputWidgetPrivate::adjustText()
{
    m_nominatimTimer.start();
}

RoutingInputWidget::RoutingInputWidget( RouteSkeleton *skeleton, int index, PluginManager* manager, QWidget *parent ) :
        QWidget( parent ), d( new RoutingInputWidgetPrivate( skeleton, index, manager, this ) )
{
    QHBoxLayout *layout = new QHBoxLayout( this );
    layout->setSpacing( 0 );
    layout->setMargin( 0 );

    layout->addWidget( d->m_pickButton );
    layout->addWidget( d->m_stateButton );
    layout->addWidget( d->m_lineEdit );
    layout->addWidget( d->m_removeButton );

    connect( d->m_stateButton, SIGNAL( clicked() ),
             this, SLOT( requestActivity() ) );
    connect( d->m_pickButton, SIGNAL( clicked( bool ) ),
             this, SLOT( setMapInputModeEnabled( bool ) ) );
    connect( d->m_removeButton, SIGNAL( clicked() ),
             this, SLOT( requestRemoval() ) );

    connect( d->m_runnerManager, SIGNAL( searchResultChanged( MarblePlacemarkModel * ) ),
             this, SLOT( setPlacemarkModel( MarblePlacemarkModel * ) ) );
    connect( d->m_runnerManager, SIGNAL( reverseGeocodingFinished( GeoDataCoordinates, GeoDataPlacemark )),
             this, SLOT(retrieveReverseGeocodingResult( GeoDataCoordinates, GeoDataPlacemark ) ) );
    connect( d->m_lineEdit, SIGNAL( returnPressed() ),
             this, SLOT( findPlacemarks() ) );
    connect( d->m_lineEdit, SIGNAL( textChanged( QString ) ),
             this, SLOT( setInvalid() ) );
    connect( &d->m_progressTimer, SIGNAL( timeout() ),
             this, SLOT( updateProgress() ) );
    connect( d->m_runnerManager, SIGNAL( searchFinished( QString ) ),
             this, SLOT( finishSearch() ) );
    connect( skeleton, SIGNAL( positionChanged( int, GeoDataCoordinates ) ),
             this, SLOT( updatePosition( int, GeoDataCoordinates ) ) );
    connect( &d->m_nominatimTimer, SIGNAL( timeout() ),
             this, SLOT( reverseGeocoding() ) );

    d->adjustText();
}

RoutingInputWidget::~RoutingInputWidget()
{
    delete d;
}

void RoutingInputWidget::reverseGeocoding()
{
    if ( d->m_workOffline || !hasTargetPosition() ) {
        return;
    }

    d->m_runnerManager->reverseGeocoding( targetPosition() );
}

void RoutingInputWidget::setPlacemarkModel( MarblePlacemarkModel *model )
{
    d->m_placemarkModel = model;
}

void RoutingInputWidget::setTargetPosition( const GeoDataCoordinates &position )
{
    if ( !hasInput() || d->m_pickButton->isChecked() ) {
        d->m_lineEdit->setText( position.toString() );
    }

    d->m_pickButton->setVisible( false );
    d->m_route->setPosition( d->m_index, position );
    d->m_progressTimer.stop();
    d->m_stateButton->setVisible( true );
    d->m_stateButton->setIcon( QIcon( d->m_route->pixmap( d->m_index ) ) );
    emit targetValidityChanged( true );
}

bool RoutingInputWidget::hasTargetPosition() const
{
    GeoDataCoordinates pos = targetPosition();
    return pos.longitude() != 0.0 && pos.latitude() != 0.0;
}

GeoDataCoordinates RoutingInputWidget::targetPosition() const
{
    return d->m_route->at( d->m_index );
}

void RoutingInputWidget::findPlacemarks()
{
    QString text = d->m_lineEdit->text();
    if ( text.isEmpty() ) {
        setInvalid();
    } else {
        d->m_pickButton->setVisible( false );
        d->m_stateButton->setVisible( true );
        d->m_progressTimer.start();
        d->m_runnerManager->findPlacemarks( text );
    }
}

MarblePlacemarkModel *RoutingInputWidget::searchResultModel()
{
    return d->m_placemarkModel;
}

void RoutingInputWidget::requestActivity()
{
    if ( hasTargetPosition() ) {
        emit activityRequest( this );
    }
}

void RoutingInputWidget::requestRemoval()
{
    emit removalRequest( this );
}

bool RoutingInputWidget::hasInput() const
{
    return !d->m_lineEdit->text().isEmpty();
}

void RoutingInputWidget::setMapInputModeEnabled( bool enabled )
{
    emit mapInputModeEnabled( this, enabled );
}

void RoutingInputWidget::updateProgress()
{
    d->m_progress.jumpToNextFrame();
    QPixmap frame = d->m_progress.currentPixmap();
    d->m_stateButton->setIcon( frame );
}

void RoutingInputWidget::finishSearch()
{
    d->m_progressTimer.stop();
    d->m_stateButton->setIcon( QIcon( d->m_route->pixmap( d->m_index ) ) );
    d->m_pickButton->setIcon( QIcon( d->m_route->pixmap( d->m_index ) ) );
    d->m_pickButton->setVisible( false );
    d->m_stateButton->setVisible( true );
    emit searchFinished( this );
}

void RoutingInputWidget::setInvalid()
{
    if ( !hasTargetPosition() ) {
        emit targetValidityChanged( false );
    }
}

void RoutingInputWidget::abortMapInputRequest()
{
    d->m_pickButton->setChecked( false );
}

void RoutingInputWidget::setIndex( int index )
{
    d->m_index = index;
    d->m_stateButton->setVisible( hasTargetPosition() );
    d->m_stateButton->setIcon( QIcon( d->m_route->pixmap( d->m_index ) ) );
    d->m_pickButton->setIcon( QIcon( d->m_route->pixmap( d->m_index ) ) );
}

void RoutingInputWidget::updatePosition( int index, const GeoDataCoordinates &position )
{
    if ( index == d->m_index ) {
        d->m_lineEdit->setText( position.toString() );
        d->m_stateButton->setVisible( hasTargetPosition() );
        d->m_stateButton->setIcon( d->m_route->pixmap( d->m_index ) );
        d->m_pickButton->setIcon( d->m_route->pixmap( d->m_index ) );
        emit targetValidityChanged( hasTargetPosition() );
        d->adjustText();
    }
}

void RoutingInputWidget::setWorkOffline( bool offline )
{
    d->m_workOffline = offline;
}

void RoutingInputWidget::clear()
{
    d->m_nominatimTimer.stop();
    d->m_progressTimer.stop();
    d->m_pickButton->setChecked( false );
    d->m_pickButton->setVisible( true );
    d->m_stateButton->setVisible( false );
    d->m_stateButton->setIcon( d->m_route->pixmap( d->m_index ) );
    d->m_route->setPosition( d->m_index, GeoDataCoordinates() );
    d->m_lineEdit->clear();
    emit targetValidityChanged( false );
}

void RoutingInputWidget::retrieveReverseGeocodingResult( const GeoDataCoordinates &, const GeoDataPlacemark &placemark )
{
    d->m_lineEdit->setText( placemark.address() );
    d->m_lineEdit->setCursorPosition( 0 );
}

} // namespace Marble

#include "RoutingInputWidget.moc"
<commit_msg>Add tr() calls to tooltips. CCBUG: 246048<commit_after>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "RoutingInputWidget.h"

#include "MarbleDebug.h"
#include "MarbleLocale.h"
#include "MarblePlacemarkModel.h"
#include "MarbleRunnerManager.h"
#include "RouteSkeleton.h"
#include "TinyWebBrowser.h"

#include <QtCore/QTimer>
#include <QtCore/QUrl>
#include <QtGui/QHBoxLayout>
#include <QtGui/QIcon>
#include <QtGui/QLineEdit>
#include <QtGui/QPushButton>
#include <QtGui/QMovie>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtXml/QDomDocument>

namespace Marble
{

class RoutingInputWidgetPrivate
{
public:
    QPushButton *m_stateButton;

    QLineEdit *m_lineEdit;

    QPushButton *m_removeButton;

    QPushButton *m_pickButton;

    MarbleRunnerManager *m_runnerManager;

    MarblePlacemarkModel *m_placemarkModel;

    QMovie m_progress;

    QTimer m_progressTimer;

    RouteSkeleton *m_route;

    int m_index;

    QNetworkAccessManager *m_manager;

    QTimer m_nominatimTimer;

    bool m_workOffline;

    /** Constructor */
    RoutingInputWidgetPrivate( RouteSkeleton *skeleton, int index, PluginManager* manager, QWidget *parent );

    /** Initiate reverse geocoding request to download address */
    void adjustText();
};

RoutingInputWidgetPrivate::RoutingInputWidgetPrivate( RouteSkeleton *skeleton, int index, PluginManager* manager, QWidget *parent ) :
        m_lineEdit( 0 ), m_runnerManager( new MarbleRunnerManager( manager, parent ) ),
        m_placemarkModel( 0 ), m_progress( ":/data/bitmaps/progress.mng" ),
        m_route( skeleton ), m_index( index ), m_manager( new QNetworkAccessManager( parent ) ),
        m_workOffline( false )
{
    m_stateButton = new QPushButton( parent );
    m_stateButton->setToolTip( QObject::tr( "Center Map here" ) );
    m_stateButton->setVisible( false );
    m_stateButton->setIcon( QIcon( m_route->pixmap( m_index ) ) );
    m_stateButton->setFlat( true );
    m_stateButton->setMaximumWidth( 22 );
    m_stateButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );

    m_lineEdit = new QLineEdit( parent );

    m_removeButton = new QPushButton( parent );
    m_removeButton->setIcon( QIcon( ":/data/bitmaps/routing_remove.png" ) );
    m_removeButton->setToolTip( QObject::tr( "Remove this position" ) );
    m_removeButton->setFlat( true );
    m_removeButton->setMaximumWidth( 22 );

    m_pickButton = new QPushButton( parent );
    m_pickButton->setIcon( QIcon( m_route->pixmap( m_index ) ) );
    m_pickButton->setToolTip( QObject::tr( "Choose position from the map" ) );
    m_pickButton->setCheckable( true );
    m_pickButton->setFlat( true );
    m_pickButton->setMaximumWidth( 22 );
    m_pickButton->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );

    m_progressTimer.setInterval( 100 );
    m_nominatimTimer.setInterval( 1000 );
    m_nominatimTimer.setSingleShot( true );

    GeoDataCoordinates pos = m_route->at( m_index );
    if ( pos.longitude() != 0.0 && pos.latitude() != 0.0 ) {
        m_lineEdit->setText( pos.toString() );
        m_pickButton->setVisible( false );
        m_stateButton->setVisible( true );
    }
}

void RoutingInputWidgetPrivate::adjustText()
{
    m_nominatimTimer.start();
}

RoutingInputWidget::RoutingInputWidget( RouteSkeleton *skeleton, int index, PluginManager* manager, QWidget *parent ) :
        QWidget( parent ), d( new RoutingInputWidgetPrivate( skeleton, index, manager, this ) )
{
    QHBoxLayout *layout = new QHBoxLayout( this );
    layout->setSpacing( 0 );
    layout->setMargin( 0 );

    layout->addWidget( d->m_pickButton );
    layout->addWidget( d->m_stateButton );
    layout->addWidget( d->m_lineEdit );
    layout->addWidget( d->m_removeButton );

    connect( d->m_stateButton, SIGNAL( clicked() ),
             this, SLOT( requestActivity() ) );
    connect( d->m_pickButton, SIGNAL( clicked( bool ) ),
             this, SLOT( setMapInputModeEnabled( bool ) ) );
    connect( d->m_removeButton, SIGNAL( clicked() ),
             this, SLOT( requestRemoval() ) );

    connect( d->m_runnerManager, SIGNAL( searchResultChanged( MarblePlacemarkModel * ) ),
             this, SLOT( setPlacemarkModel( MarblePlacemarkModel * ) ) );
    connect( d->m_runnerManager, SIGNAL( reverseGeocodingFinished( GeoDataCoordinates, GeoDataPlacemark )),
             this, SLOT(retrieveReverseGeocodingResult( GeoDataCoordinates, GeoDataPlacemark ) ) );
    connect( d->m_lineEdit, SIGNAL( returnPressed() ),
             this, SLOT( findPlacemarks() ) );
    connect( d->m_lineEdit, SIGNAL( textChanged( QString ) ),
             this, SLOT( setInvalid() ) );
    connect( &d->m_progressTimer, SIGNAL( timeout() ),
             this, SLOT( updateProgress() ) );
    connect( d->m_runnerManager, SIGNAL( searchFinished( QString ) ),
             this, SLOT( finishSearch() ) );
    connect( skeleton, SIGNAL( positionChanged( int, GeoDataCoordinates ) ),
             this, SLOT( updatePosition( int, GeoDataCoordinates ) ) );
    connect( &d->m_nominatimTimer, SIGNAL( timeout() ),
             this, SLOT( reverseGeocoding() ) );

    d->adjustText();
}

RoutingInputWidget::~RoutingInputWidget()
{
    delete d;
}

void RoutingInputWidget::reverseGeocoding()
{
    if ( d->m_workOffline || !hasTargetPosition() ) {
        return;
    }

    d->m_runnerManager->reverseGeocoding( targetPosition() );
}

void RoutingInputWidget::setPlacemarkModel( MarblePlacemarkModel *model )
{
    d->m_placemarkModel = model;
}

void RoutingInputWidget::setTargetPosition( const GeoDataCoordinates &position )
{
    if ( !hasInput() || d->m_pickButton->isChecked() ) {
        d->m_lineEdit->setText( position.toString() );
    }

    d->m_pickButton->setVisible( false );
    d->m_route->setPosition( d->m_index, position );
    d->m_progressTimer.stop();
    d->m_stateButton->setVisible( true );
    d->m_stateButton->setIcon( QIcon( d->m_route->pixmap( d->m_index ) ) );
    emit targetValidityChanged( true );
}

bool RoutingInputWidget::hasTargetPosition() const
{
    GeoDataCoordinates pos = targetPosition();
    return pos.longitude() != 0.0 && pos.latitude() != 0.0;
}

GeoDataCoordinates RoutingInputWidget::targetPosition() const
{
    return d->m_route->at( d->m_index );
}

void RoutingInputWidget::findPlacemarks()
{
    QString text = d->m_lineEdit->text();
    if ( text.isEmpty() ) {
        setInvalid();
    } else {
        d->m_pickButton->setVisible( false );
        d->m_stateButton->setVisible( true );
        d->m_progressTimer.start();
        d->m_runnerManager->findPlacemarks( text );
    }
}

MarblePlacemarkModel *RoutingInputWidget::searchResultModel()
{
    return d->m_placemarkModel;
}

void RoutingInputWidget::requestActivity()
{
    if ( hasTargetPosition() ) {
        emit activityRequest( this );
    }
}

void RoutingInputWidget::requestRemoval()
{
    emit removalRequest( this );
}

bool RoutingInputWidget::hasInput() const
{
    return !d->m_lineEdit->text().isEmpty();
}

void RoutingInputWidget::setMapInputModeEnabled( bool enabled )
{
    emit mapInputModeEnabled( this, enabled );
}

void RoutingInputWidget::updateProgress()
{
    d->m_progress.jumpToNextFrame();
    QPixmap frame = d->m_progress.currentPixmap();
    d->m_stateButton->setIcon( frame );
}

void RoutingInputWidget::finishSearch()
{
    d->m_progressTimer.stop();
    d->m_stateButton->setIcon( QIcon( d->m_route->pixmap( d->m_index ) ) );
    d->m_pickButton->setIcon( QIcon( d->m_route->pixmap( d->m_index ) ) );
    d->m_pickButton->setVisible( false );
    d->m_stateButton->setVisible( true );
    emit searchFinished( this );
}

void RoutingInputWidget::setInvalid()
{
    if ( !hasTargetPosition() ) {
        emit targetValidityChanged( false );
    }
}

void RoutingInputWidget::abortMapInputRequest()
{
    d->m_pickButton->setChecked( false );
}

void RoutingInputWidget::setIndex( int index )
{
    d->m_index = index;
    d->m_stateButton->setVisible( hasTargetPosition() );
    d->m_stateButton->setIcon( QIcon( d->m_route->pixmap( d->m_index ) ) );
    d->m_pickButton->setIcon( QIcon( d->m_route->pixmap( d->m_index ) ) );
}

void RoutingInputWidget::updatePosition( int index, const GeoDataCoordinates &position )
{
    if ( index == d->m_index ) {
        d->m_lineEdit->setText( position.toString() );
        d->m_stateButton->setVisible( hasTargetPosition() );
        d->m_stateButton->setIcon( d->m_route->pixmap( d->m_index ) );
        d->m_pickButton->setIcon( d->m_route->pixmap( d->m_index ) );
        emit targetValidityChanged( hasTargetPosition() );
        d->adjustText();
    }
}

void RoutingInputWidget::setWorkOffline( bool offline )
{
    d->m_workOffline = offline;
}

void RoutingInputWidget::clear()
{
    d->m_nominatimTimer.stop();
    d->m_progressTimer.stop();
    d->m_pickButton->setChecked( false );
    d->m_pickButton->setVisible( true );
    d->m_stateButton->setVisible( false );
    d->m_stateButton->setIcon( d->m_route->pixmap( d->m_index ) );
    d->m_route->setPosition( d->m_index, GeoDataCoordinates() );
    d->m_lineEdit->clear();
    emit targetValidityChanged( false );
}

void RoutingInputWidget::retrieveReverseGeocodingResult( const GeoDataCoordinates &, const GeoDataPlacemark &placemark )
{
    d->m_lineEdit->setText( placemark.address() );
    d->m_lineEdit->setCursorPosition( 0 );
}

} // namespace Marble

#include "RoutingInputWidget.moc"
<|endoftext|>


<commit_before>#pragma once

#include <geneial/core/operations/crossover/MultiValuePermutationCrossover.h>
#include <geneial/utility/Random.h>

geneial_private_namespace(geneial)
{
geneial_private_namespace(operation)
{
geneial_private_namespace(crossover)
{
using ::geneial::population::Population;
using ::geneial::population::chromosome::MultiValueChromosome;
using ::geneial::operation::coupling::BaseCouplingOperation;
using ::geneial::utility::Random;

enum COPY_MODE
{
	COPY_LEFT_PART,
	COPY_RIGHT_PART
};

template<typename VALUE_TYPE, typename FITNESS_TYPE>
void copyContainerPart(const typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::value_container& source,
					   typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::value_container& dest,
					   COPY_MODE mode,
					   const unsigned int separator
)
{
	assert(separator < source.size());
	assert(separator >= 0);
	assert(separator < dest.size());

	if(mode == COPY_MODE::COPY_LEFT_PART)
	{
		std::copy(source.begin() , source.begin() + separator + 1, dest.begin());
	}
	else //RIGHT PART
	{
		std::copy(source.begin() + separator , source.end(), dest.begin() + separator);
	}
}

template<typename VALUE_TYPE, typename FITNESS_TYPE>
void copyRemainder(const typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::value_container& source,
				   typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::value_container& dest,
				   COPY_MODE alreadyCopied,
				   const unsigned int separator)
{
	if(alreadyCopied == COPY_MODE::COPY_LEFT_PART)
	{
		//We need to copy everything to begin()  --> end() from source
		//Values already present are in begin() --> begin() + separator of dest
		unsigned int nextSourcePos = 0;
		for(unsigned int nextCopyPos = separator + 1; nextCopyPos < dest.size(); nextCopyPos ++)
		{
			//Find a value that we can copy.
			for(; nextSourcePos < source.size();nextSourcePos++)
			{
				//Do we have this value already?
				if(std::find( dest.begin(), dest.begin() + nextCopyPos, source[nextSourcePos]) != dest.begin() + nextCopyPos)
				{
					continue;
				}
				else
				{
					break;
				}
			}
			dest[nextCopyPos] = source[nextSourcePos];
			nextSourcePos++;
		}
	}
	else // Right Part was copied
	{
		//We need to copy everything to begin()  --> end() from source what is not contained in dest
		//Values already present are in begin() + separator --> end() separator of dest
		unsigned int nextSourcePos = 0;
		for(int nextCopyPos = separator -1 ; nextCopyPos >= 0; nextCopyPos --)
		{
			//Find a value that we can copy.
			for(; nextSourcePos < source.size();nextSourcePos++)
			{
				//Do we have this value already?
				if(std::find( dest.begin()+nextCopyPos + 1, dest.end(), source[nextSourcePos]) != dest.end())
				{
					continue;
				}
				else
				{
					break;
				}
			}
			dest[nextCopyPos] = source[nextSourcePos];
			nextSourcePos++;
		}
	}
}

geneial_export_namespace
{

template<typename VALUE_TYPE, typename FITNESS_TYPE>
typename BaseCrossoverOperation<FITNESS_TYPE>::crossover_result_set MultiValuePermutationCrossover<VALUE_TYPE,
        FITNESS_TYPE>::doMultiValueCrossover(
        const typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::const_ptr &mommy,
        const typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::const_ptr &daddy) const
{

    typename BaseCouplingOperation<FITNESS_TYPE>::offspring_result_set resultset;

    auto child_candidate = this->createChildCandidate();

    const auto &daddy_container = daddy->getContainer();
    const auto &mommy_container = mommy->getContainer();

    auto &child_container = child_candidate->getContainer();

    assert(daddy_container.size() == mommy_container.size());

    COPY_MODE copyMode = Random::generateBit() ? COPY_MODE::COPY_LEFT_PART : COPY_MODE::COPY_RIGHT_PART;
    auto startWithMommy = Random::generateBit();
    const unsigned int where = Random::generate<int>(0, daddy_container.size() -1 );

    child_container.resize(daddy_container.size(),0);

    copyContainerPart<VALUE_TYPE,FITNESS_TYPE>(startWithMommy?mommy_container:daddy_container, child_container, copyMode, where);
    copyRemainder<VALUE_TYPE,FITNESS_TYPE>(startWithMommy?daddy_container:mommy_container, child_container, copyMode, where);

    assert(std::accumulate(child_container.begin(),child_container.end(),0) == 6);

    //Now some parts of the container have elements of mommy/daddy.
    //Next we need to fill up the gap with

    resultset.emplace_back(std::move(child_candidate));
    return std::move(resultset);
}

} /* geneial_export_namespace */
} /* private namespace crossover */
} /* private namespace operation */
} /* private namespace geneial */

<commit_msg>remove debugging assertion<commit_after>#pragma once

#include <geneial/core/operations/crossover/MultiValuePermutationCrossover.h>
#include <geneial/utility/Random.h>

geneial_private_namespace(geneial)
{
geneial_private_namespace(operation)
{
geneial_private_namespace(crossover)
{
using ::geneial::population::Population;
using ::geneial::population::chromosome::MultiValueChromosome;
using ::geneial::operation::coupling::BaseCouplingOperation;
using ::geneial::utility::Random;

enum COPY_MODE
{
	COPY_LEFT_PART,
	COPY_RIGHT_PART
};

template<typename VALUE_TYPE, typename FITNESS_TYPE>
void copyContainerPart(const typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::value_container& source,
					   typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::value_container& dest,
					   COPY_MODE mode,
					   const unsigned int separator
)
{
	assert(separator < source.size());
	assert(separator >= 0);
	assert(separator < dest.size());

	if(mode == COPY_MODE::COPY_LEFT_PART)
	{
		std::copy(source.begin() , source.begin() + separator + 1, dest.begin());
	}
	else //RIGHT PART
	{
		std::copy(source.begin() + separator , source.end(), dest.begin() + separator);
	}
}

template<typename VALUE_TYPE, typename FITNESS_TYPE>
void copyRemainder(const typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::value_container& source,
				   typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::value_container& dest,
				   COPY_MODE alreadyCopied,
				   const unsigned int separator)
{
	if(alreadyCopied == COPY_MODE::COPY_LEFT_PART)
	{
		//We need to copy everything to begin()  --> end() from source
		//Values already present are in begin() --> begin() + separator of dest
		unsigned int nextSourcePos = 0;
		for(unsigned int nextCopyPos = separator + 1; nextCopyPos < dest.size(); nextCopyPos ++)
		{
			//Find a value that we can copy.
			for(; nextSourcePos < source.size();nextSourcePos++)
			{
				//Do we have this value already?
				if(std::find( dest.begin(), dest.begin() + nextCopyPos, source[nextSourcePos]) != dest.begin() + nextCopyPos)
				{
					continue;
				}
				else
				{
					break;
				}
			}
			dest[nextCopyPos] = source[nextSourcePos];
			nextSourcePos++;
		}
	}
	else // Right Part was copied
	{
		//We need to copy everything to begin()  --> end() from source what is not contained in dest
		//Values already present are in begin() + separator --> end() separator of dest
		unsigned int nextSourcePos = 0;
		for(int nextCopyPos = separator -1 ; nextCopyPos >= 0; nextCopyPos --)
		{
			//Find a value that we can copy.
			for(; nextSourcePos < source.size();nextSourcePos++)
			{
				//Do we have this value already?
				if(std::find( dest.begin()+nextCopyPos + 1, dest.end(), source[nextSourcePos]) != dest.end())
				{
					continue;
				}
				else
				{
					break;
				}
			}
			dest[nextCopyPos] = source[nextSourcePos];
			nextSourcePos++;
		}
	}
}

geneial_export_namespace
{

template<typename VALUE_TYPE, typename FITNESS_TYPE>
typename BaseCrossoverOperation<FITNESS_TYPE>::crossover_result_set MultiValuePermutationCrossover<VALUE_TYPE,
        FITNESS_TYPE>::doMultiValueCrossover(
        const typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::const_ptr &mommy,
        const typename MultiValueChromosome<VALUE_TYPE, FITNESS_TYPE>::const_ptr &daddy) const
{

    typename BaseCouplingOperation<FITNESS_TYPE>::offspring_result_set resultset;

    auto child_candidate = this->createChildCandidate();

    const auto &daddy_container = daddy->getContainer();
    const auto &mommy_container = mommy->getContainer();

    auto &child_container = child_candidate->getContainer();

    assert(daddy_container.size() == mommy_container.size());

    COPY_MODE copyMode = Random::generateBit() ? COPY_MODE::COPY_LEFT_PART : COPY_MODE::COPY_RIGHT_PART;
    auto startWithMommy = Random::generateBit();
    const unsigned int where = Random::generate<int>(0, daddy_container.size() -1 );

    child_container.resize(daddy_container.size(),0);

    copyContainerPart<VALUE_TYPE,FITNESS_TYPE>(startWithMommy?mommy_container:daddy_container, child_container, copyMode, where);
    copyRemainder<VALUE_TYPE,FITNESS_TYPE>(startWithMommy?daddy_container:mommy_container, child_container, copyMode, where);

    //Now some parts of the container have elements of mommy/daddy.
    //Next we need to fill up the gap with

    resultset.emplace_back(std::move(child_candidate));
    return std::move(resultset);
}

} /* geneial_export_namespace */
} /* private namespace crossover */
} /* private namespace operation */
} /* private namespace geneial */
<|endoftext|>


<commit_before><commit_msg>Fix mistake in the supports_expression macro.<commit_after><|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

#ifndef __MESOS_CONTAINERIZER_HPP__
#define __MESOS_CONTAINERIZER_HPP__

#include <list>
#include <vector>

#include <stout/hashmap.hpp>
#include <stout/multihashmap.hpp>

#include "slave/containerizer/containerizer.hpp"
#include "slave/containerizer/isolator.hpp"
#include "slave/containerizer/launcher.hpp"

namespace mesos {
namespace internal {
namespace slave {

// Forward declaration.
class MesosContainerizerProcess;

class MesosContainerizer : public Containerizer
{
public:
  static Try<MesosContainerizer*> create(
      const Flags& flags,
      bool local,
      Fetcher* fetcher);

  MesosContainerizer(
      const Flags& flags,
      bool local,
      Fetcher* fetcher,
      const process::Owned<Launcher>& launcher,
      const std::vector<process::Owned<Isolator>>& isolators);

  // Used for testing.
  MesosContainerizer(const process::Owned<MesosContainerizerProcess>& _process);

  virtual ~MesosContainerizer();

  virtual process::Future<Nothing> recover(
      const Option<state::SlaveState>& state);

  virtual process::Future<bool> launch(
      const ContainerID& containerId,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user,
      const SlaveID& slaveId,
      const process::PID<Slave>& slavePid,
      bool checkpoint);

  virtual process::Future<bool> launch(
      const ContainerID& containerId,
      const TaskInfo& taskInfo,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user,
      const SlaveID& slaveId,
      const process::PID<Slave>& slavePid,
      bool checkpoint);

  virtual process::Future<Nothing> update(
      const ContainerID& containerId,
      const Resources& resources);

  virtual process::Future<ResourceStatistics> usage(
      const ContainerID& containerId);

  virtual process::Future<containerizer::Termination> wait(
      const ContainerID& containerId);

  virtual void destroy(const ContainerID& containerId);

  virtual process::Future<hashset<ContainerID>> containers();

private:
  process::Owned<MesosContainerizerProcess> process;
};

class MesosContainerizerProcess
  : public process::Process<MesosContainerizerProcess>
{
public:
  MesosContainerizerProcess(
      const Flags& _flags,
      bool _local,
      Fetcher* _fetcher,
      const process::Owned<Launcher>& _launcher,
      const std::vector<process::Owned<Isolator>>& _isolators)
    : flags(_flags),
      local(_local),
      fetcher(_fetcher),
      launcher(_launcher),
      isolators(_isolators) {}

  virtual ~MesosContainerizerProcess() {}

  virtual process::Future<Nothing> recover(
      const Option<state::SlaveState>& state);

  virtual process::Future<bool> launch(
      const ContainerID& containerId,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user,
      const SlaveID& slaveId,
      const process::PID<Slave>& slavePid,
      bool checkpoint);

  virtual process::Future<bool> launch(
      const ContainerID& containerId,
      const TaskInfo& taskInfo,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user,
      const SlaveID& slaveId,
      const process::PID<Slave>& slavePid,
      bool checkpoint);

  virtual process::Future<Nothing> update(
      const ContainerID& containerId,
      const Resources& resources);

  virtual process::Future<ResourceStatistics> usage(
      const ContainerID& containerId);

  virtual process::Future<containerizer::Termination> wait(
      const ContainerID& containerId);

  virtual process::Future<bool> exec(
      const ContainerID& containerId,
      int pipeWrite);

  virtual void destroy(const ContainerID& containerId);

  virtual process::Future<hashset<ContainerID>> containers();

private:
  process::Future<Nothing> _recover(
      const std::list<state::RunState>& recoverable);

  process::Future<Nothing> __recover(
      const std::list<state::RunState>& recovered);

  process::Future<std::list<Option<CommandInfo>>> prepare(
      const ContainerID& containerId,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user);

  process::Future<Nothing> fetch(
      const ContainerID& containerId,
      const CommandInfo& commandInfo,
      const std::string& directory,
      const Option<std::string>& user);

  process::Future<bool> _launch(
      const ContainerID& containerId,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user,
      const SlaveID& slaveId,
      const process::PID<Slave>& slavePid,
      bool checkpoint,
      const std::list<Option<CommandInfo>>& scripts);

  process::Future<bool> isolate(
      const ContainerID& containerId,
      pid_t _pid);

  // Continues 'destroy()' once isolators has completed.
  void _destroy(const ContainerID& containerId);

  // Continues 'destroy()' once all processes have been killed by the launcher.
  void __destroy(
      const ContainerID& containerId,
      const process::Future<Nothing>& future);

  // Continues '_destroy()' once we get the exit status of the executor.
  void ___destroy(
      const ContainerID& containerId,
      const process::Future<Option<int>>& status);

  // Continues (and completes) '__destroy()' once all isolators have completed
  // cleanup.
  void ____destroy(
      const ContainerID& containerId,
      const process::Future<Option<int>>& status,
      const process::Future<std::list<process::Future<Nothing>>>& cleanups);

  // Call back for when an isolator limits a container and impacts the
  // processes. This will trigger container destruction.
  void limited(
      const ContainerID& containerId,
      const process::Future<Limitation>& future);

  // Call back for when the executor exits. This will trigger container
  // destroy.
  void reaped(const ContainerID& containerId);

  const Flags flags;
  const bool local;
  Fetcher* fetcher;
  const process::Owned<Launcher> launcher;
  const std::vector<process::Owned<Isolator>> isolators;

  enum State
  {
    PREPARING,
    ISOLATING,
    FETCHING,
    RUNNING,
    DESTROYING
  };

  struct Container
  {
    // Promise for futures returned from wait().
    process::Promise<containerizer::Termination> promise;

    // We need to keep track of the future exit status for each
    // executor because we'll only get a single notification when
    // the executor exits.
    process::Future<Option<int>> status;

    // We keep track of the future that is waiting for all the
    // isolator's futures, so that destroy will only start calling
    // cleanup after all isolators has finished isolating.
    process::Future<std::list<Nothing>> isolation;

    // We keep track of any limitations received from each isolator so we can
    // determine the cause of an executor termination.
    std::vector<Limitation> limitations;

    // We keep track of the resources for each container so we can set the
    // ResourceStatistics limits in usage().
    Resources resources;

    State state;
  };

  hashmap<ContainerID, process::Owned<Container>> containers_;
};

} // namespace slave {
} // namespace internal {
} // namespace mesos {

#endif // __MESOS_CONTAINERIZER_HPP__
<commit_msg>Add an optional container rootfs for MesosContainerizer.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

#ifndef __MESOS_CONTAINERIZER_HPP__
#define __MESOS_CONTAINERIZER_HPP__

#include <list>
#include <vector>

#include <stout/hashmap.hpp>
#include <stout/multihashmap.hpp>

#include "slave/containerizer/containerizer.hpp"
#include "slave/containerizer/isolator.hpp"
#include "slave/containerizer/launcher.hpp"

namespace mesos {
namespace internal {
namespace slave {

// Forward declaration.
class MesosContainerizerProcess;

class MesosContainerizer : public Containerizer
{
public:
  static Try<MesosContainerizer*> create(
      const Flags& flags,
      bool local,
      Fetcher* fetcher);

  MesosContainerizer(
      const Flags& flags,
      bool local,
      Fetcher* fetcher,
      const process::Owned<Launcher>& launcher,
      const std::vector<process::Owned<Isolator>>& isolators);

  // Used for testing.
  MesosContainerizer(const process::Owned<MesosContainerizerProcess>& _process);

  virtual ~MesosContainerizer();

  virtual process::Future<Nothing> recover(
      const Option<state::SlaveState>& state);

  virtual process::Future<bool> launch(
      const ContainerID& containerId,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user,
      const SlaveID& slaveId,
      const process::PID<Slave>& slavePid,
      bool checkpoint);

  virtual process::Future<bool> launch(
      const ContainerID& containerId,
      const TaskInfo& taskInfo,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user,
      const SlaveID& slaveId,
      const process::PID<Slave>& slavePid,
      bool checkpoint);

  virtual process::Future<Nothing> update(
      const ContainerID& containerId,
      const Resources& resources);

  virtual process::Future<ResourceStatistics> usage(
      const ContainerID& containerId);

  virtual process::Future<containerizer::Termination> wait(
      const ContainerID& containerId);

  virtual void destroy(const ContainerID& containerId);

  virtual process::Future<hashset<ContainerID>> containers();

private:
  process::Owned<MesosContainerizerProcess> process;
};

class MesosContainerizerProcess
  : public process::Process<MesosContainerizerProcess>
{
public:
  MesosContainerizerProcess(
      const Flags& _flags,
      bool _local,
      Fetcher* _fetcher,
      const process::Owned<Launcher>& _launcher,
      const std::vector<process::Owned<Isolator>>& _isolators)
    : flags(_flags),
      local(_local),
      fetcher(_fetcher),
      launcher(_launcher),
      isolators(_isolators) {}

  virtual ~MesosContainerizerProcess() {}

  virtual process::Future<Nothing> recover(
      const Option<state::SlaveState>& state);

  virtual process::Future<bool> launch(
      const ContainerID& containerId,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user,
      const SlaveID& slaveId,
      const process::PID<Slave>& slavePid,
      bool checkpoint);

  virtual process::Future<bool> launch(
      const ContainerID& containerId,
      const TaskInfo& taskInfo,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user,
      const SlaveID& slaveId,
      const process::PID<Slave>& slavePid,
      bool checkpoint);

  virtual process::Future<Nothing> update(
      const ContainerID& containerId,
      const Resources& resources);

  virtual process::Future<ResourceStatistics> usage(
      const ContainerID& containerId);

  virtual process::Future<containerizer::Termination> wait(
      const ContainerID& containerId);

  virtual process::Future<bool> exec(
      const ContainerID& containerId,
      int pipeWrite);

  virtual void destroy(const ContainerID& containerId);

  virtual process::Future<hashset<ContainerID>> containers();

private:
  process::Future<Nothing> _recover(
      const std::list<state::RunState>& recoverable);

  process::Future<Nothing> __recover(
      const std::list<state::RunState>& recovered);

  process::Future<std::list<Option<CommandInfo>>> prepare(
      const ContainerID& containerId,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user);

  process::Future<Nothing> fetch(
      const ContainerID& containerId,
      const CommandInfo& commandInfo,
      const std::string& directory,
      const Option<std::string>& user);

  process::Future<bool> _launch(
      const ContainerID& containerId,
      const ExecutorInfo& executorInfo,
      const std::string& directory,
      const Option<std::string>& user,
      const SlaveID& slaveId,
      const process::PID<Slave>& slavePid,
      bool checkpoint,
      const std::list<Option<CommandInfo>>& scripts);

  process::Future<bool> isolate(
      const ContainerID& containerId,
      pid_t _pid);

  // Continues 'destroy()' once isolators has completed.
  void _destroy(const ContainerID& containerId);

  // Continues 'destroy()' once all processes have been killed by the launcher.
  void __destroy(
      const ContainerID& containerId,
      const process::Future<Nothing>& future);

  // Continues '_destroy()' once we get the exit status of the executor.
  void ___destroy(
      const ContainerID& containerId,
      const process::Future<Option<int>>& status);

  // Continues (and completes) '__destroy()' once all isolators have completed
  // cleanup.
  void ____destroy(
      const ContainerID& containerId,
      const process::Future<Option<int>>& status,
      const process::Future<std::list<process::Future<Nothing>>>& cleanups);

  // Call back for when an isolator limits a container and impacts the
  // processes. This will trigger container destruction.
  void limited(
      const ContainerID& containerId,
      const process::Future<Limitation>& future);

  // Call back for when the executor exits. This will trigger container
  // destroy.
  void reaped(const ContainerID& containerId);

  const Flags flags;
  const bool local;
  Fetcher* fetcher;
  const process::Owned<Launcher> launcher;
  const std::vector<process::Owned<Isolator>> isolators;

  enum State
  {
    PREPARING,
    ISOLATING,
    FETCHING,
    RUNNING,
    DESTROYING
  };

  struct Container
  {
    // Promise for futures returned from wait().
    process::Promise<containerizer::Termination> promise;

    // We need to keep track of the future exit status for each
    // executor because we'll only get a single notification when
    // the executor exits.
    process::Future<Option<int>> status;

    // We keep track of the future that is waiting for all the
    // isolator's futures, so that destroy will only start calling
    // cleanup after all isolators has finished isolating.
    process::Future<std::list<Nothing>> isolation;

    // We keep track of any limitations received from each isolator so we can
    // determine the cause of an executor termination.
    std::vector<Limitation> limitations;

    // We keep track of the resources for each container so we can set the
    // ResourceStatistics limits in usage().
    Resources resources;

    // The path to the container's rootfs, if full filesystem
    // isolation is used.
    Option<std::string> rootfs;

    State state;
  };

  hashmap<ContainerID, process::Owned<Container>> containers_;
};

} // namespace slave {
} // namespace internal {
} // namespace mesos {

#endif // __MESOS_CONTAINERIZER_HPP__
<|endoftext|>


<commit_before>/******************************************************************************
 Copyright 2019 Allied Telesis Labs Ltd. 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/

#include <buildsys.h>

static bool directory_exists(const std::string & dir)
{
	if(!filesystem::exists(dir)) {
		/* Nothing here */
		return false;
	} else if(buildsys::filesystem::is_directory(dir)) {
		/* Actually a directory */
		return true;
	}
	/* Something other than a directory */
	return false;
}

static bool refspec_is_commitid(const std::string & refspec)
{
	if(refspec.length() != 40) {
		return false;
	}

	for(char const &c:refspec) {
		if(!isxdigit(c)) {
			return false;
		}
	}

	return true;
}

static std::string git_hash_ref(const std::string & gdir, const std::string & refspec)
{
	std::string cmd = string_format("cd %s && git rev-parse %s", gdir.c_str(),
					refspec.c_str());
	FILE *f = popen(cmd.c_str(), "r");
	if(f == NULL) {
		throw CustomException("git rev-parse ref failed");
	}
	char *commit = (char *) calloc(41, sizeof(char));
	fread(commit, sizeof(char), 40, f);
	pclose(f);

	std::string ret = std::string(commit);
	free(commit);

	return ret;
}

static std::string git_hash(const std::string & gdir)
{
	return git_hash_ref(gdir, "HEAD");
}

static std::string git_diff_hash(const std::string & gdir)
{
	std::string cmd = string_format("cd %s && git diff HEAD | sha1sum", gdir.c_str());
	FILE *f = popen(cmd.c_str(), "r");
	if(f == NULL) {
		throw CustomException("git diff | sha1sum failed");
	}
	char *delta_hash = (char *) calloc(41, sizeof(char));
	fread(delta_hash, sizeof(char), 40, f);
	pclose(f);
	std::string ret(delta_hash);
	free(delta_hash);
	return ret;
}

static std::string git_remote(const std::string & gdir, const std::string & remote)
{
	std::string cmd = string_format("cd %s && git config --local --get remote.%s.url",
					gdir.c_str(), remote.c_str());
	FILE *f = popen(cmd.c_str(), "r");
	if(f == NULL) {
		throw CustomException("git config --local --get remote. .url failed");
	}
	char *Remote = (char *) calloc(1025, sizeof(char));
	fread(Remote, sizeof(char), 1024, f);
	pclose(f);
	std::string ret(Remote);
	free(Remote);
	return ret;
}

GitDirExtractionUnit::GitDirExtractionUnit(const std::string & git_dir,
					   const std::string & to_dir)
{
	this->uri = git_dir;
	this->hash = git_hash(this->uri);
	this->toDir = to_dir;
}

GitDirExtractionUnit::GitDirExtractionUnit()
{
}

bool GitDirExtractionUnit::isDirty()
{
	if(!directory_exists(this->localPath())) {
		/* If the source directory doesn't exist, then it can't be dirty */
		return false;
	}

	std::string cmd = string_format("cd %s && git diff --quiet HEAD",
					this->localPath().c_str());
	int res = std::system(cmd.c_str());
	return (res != 0);
}

std::string GitDirExtractionUnit::dirtyHash()
{
	return git_diff_hash(this->localPath());
}

GitExtractionUnit::GitExtractionUnit(const std::string & remote, const std::string & local,
				     std::string refspec, Package * P)
{
	this->uri = remote;
	this->local = P->getWorld()->getWorkingDir() + "/source/" + local;
	this->refspec = refspec;
	this->P = P;
	this->fetched = false;
}

bool GitExtractionUnit::updateOrigin()
{
	std::string location = this->uri;
	std::string source_dir = this->local;
	std::string remote_url = git_remote(source_dir, "origin");

	if(remote_url != location) {
		PackageCmd pc(source_dir.c_str(), "git");
		pc.addArg("remote");
		// If the remote doesn't exist, add it
		if(remote_url == "") {
			pc.addArg("add");
		} else {
			pc.addArg("set-url");
		}
		pc.addArg("origin");
		pc.addArg(location.c_str());
		if(!pc.Run(this->P)) {
			throw CustomException("Failed: git remote set-url origin");
		}

		pc = PackageCmd(source_dir.c_str(), "git");
		pc.addArg("fetch");
		pc.addArg("origin");
		pc.addArg("--tags");
		if(!pc.Run(this->P)) {
			throw CustomException("Failed: git fetch origin --tags");
		}
	}

	return true;
}

bool GitExtractionUnit::fetch(BuildDir * d)
{
	std::string location = this->uri;
	std::string source_dir = this->local;
	std::string cwd = d->getWorld()->getWorkingDir();

	bool exists = directory_exists(source_dir);

	PackageCmd pc(exists ? source_dir : cwd, "git");

	if(exists) {
		/* Update the origin */
		this->updateOrigin();
		/* Check if the commit is already present */
		std::string cmd =
		    "cd " + source_dir + "; git cat-file -e " + this->refspec +
		    " 2>/dev/null";
		if(std::system(cmd.c_str()) != 0) {
			/* If not, fetch everything from origin */
			pc.addArg("fetch");
			pc.addArg("origin");
			pc.addArg("--tags");
			if(!pc.Run(this->P)) {
				throw CustomException("Failed: git fetch origin --tags");
			}
		}
	} else {
		pc.addArg("clone");
		pc.addArg("-n");
		pc.addArg(location.c_str());
		pc.addArg(source_dir.c_str());
		if(!pc.Run(this->P))
			throw CustomException("Failed to git clone");
	}

	if(this->refspec.compare("HEAD") == 0) {
		// Don't touch it
	} else {
		std::string cmd =
		    "cd " + source_dir +
		    "; git show-ref --quiet --verify -- refs/heads/" + this->refspec;
		if(std::system(cmd.c_str()) == 0) {
			std::string head_hash = git_hash_ref(source_dir, "HEAD");
			std::string branch_hash = git_hash_ref(source_dir, this->refspec);
			if(head_hash != branch_hash) {
				throw CustomException("Asked to use branch: " +
						      this->refspec + ", but " +
						      source_dir +
						      " is off somewhere else");
			}
		} else {
			pc = PackageCmd(source_dir.c_str(), "git");
			// switch to refspec
			pc.addArg("checkout");
			pc.addArg("-q");
			pc.addArg("--detach");
			pc.addArg(this->refspec.c_str());
			if(!pc.Run(this->P))
				throw CustomException("Failed to checkout");
		}
	}
	bool res = true;

	std::string hash = git_hash(source_dir);

	if(!this->hash.empty()) {
		if(this->hash != hash) {
			log(this->P,
			    "Hash mismatch for %s\n(committed to %s, providing %s)\n",
			    this->uri.c_str(), this->hash.c_str(), hash.c_str());
			res = false;
		}
	} else {
		this->hash = hash;
	}

	this->fetched = res;

	return res;
}

std::string GitExtractionUnit::HASH()
{
	if(refspec_is_commitid(this->refspec)) {
		this->hash = std::string(this->refspec);
	} else {
		std::string digest_name = string_format("%s#%s", this->uri.c_str(),
							this->refspec.c_str());
		/* Check if the package contains pre-computed hashes */
		std::string Hash = P->getFileHash(digest_name);
		if(Hash.empty()) {
			this->fetch(P->builddir());
		} else {
			this->hash = Hash;
		}
	}
	return this->hash;
}

bool GitExtractionUnit::extract(Package * P, BuildDir * bd)
{
	// make sure it has been fetched
	if(!this->fetched) {
		if(!this->fetch(bd)) {
			return false;
		}
	}
	// copy to work dir
	PackageCmd pc(bd->getPath(), "cp");
	pc.addArg("-dpRuf");
	pc.addArg(this->localPath());
	pc.addArg(".");
	if(!pc.Run(P))
		throw CustomException("Failed to checkout");

	return true;
}

bool LinkGitDirExtractionUnit::extract(Package * P, BuildDir * bd)
{
	PackageCmd pc(bd->getPath(), "ln");

	pc.addArg("-sfT");

	if(this->uri.at(0) == '.') {
		std::string arg = P->getWorld()->getWorkingDir() + "/" + this->uri;
		pc.addArg(arg);
	} else {
		pc.addArg(this->uri);
	}
	pc.addArg(this->toDir);

	if(!pc.Run(P)) {
		throw CustomException("Operation failed");
	}

	return true;
}

bool CopyGitDirExtractionUnit::extract(Package * P, BuildDir * bd)
{
	PackageCmd pc(bd->getPath(), "cp");
	pc.addArg("-dpRuf");

	if(this->uri.at(0) == '.') {
		std::string arg = P->getWorld()->getWorkingDir() + "/" + this->uri;
		pc.addArg(arg);
	} else {
		pc.addArg(this->uri);
	}
	pc.addArg(this->toDir);

	if(!pc.Run(P)) {
		throw CustomException("Operation failed");
	}

	return true;
}
<commit_msg>extraction/git: Remove usages of calloc<commit_after>/******************************************************************************
 Copyright 2019 Allied Telesis Labs Ltd. 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/

#include <buildsys.h>

static bool directory_exists(const std::string & dir)
{
	if(!filesystem::exists(dir)) {
		/* Nothing here */
		return false;
	} else if(buildsys::filesystem::is_directory(dir)) {
		/* Actually a directory */
		return true;
	}
	/* Something other than a directory */
	return false;
}

static bool refspec_is_commitid(const std::string & refspec)
{
	if(refspec.length() != 40) {
		return false;
	}

	for(char const &c:refspec) {
		if(!isxdigit(c)) {
			return false;
		}
	}

	return true;
}

static std::string git_hash_ref(const std::string & gdir, const std::string & refspec)
{
	std::string cmd = "cd " + gdir + " && git rev-parse " + refspec;
	FILE *f = popen(cmd.c_str(), "r");
	if(f == NULL) {
		throw CustomException("git rev-parse ref failed");
	}
	char commit[41] = {};
	fread(commit, sizeof(char), 40, f);
	pclose(f);

	return std::string(commit);
}

static std::string git_hash(const std::string & gdir)
{
	return git_hash_ref(gdir, "HEAD");
}

static std::string git_diff_hash(const std::string & gdir)
{
	std::string cmd = "cd " + gdir + " && git diff HEAD | sha1sum";
	FILE *f = popen(cmd.c_str(), "r");
	if(f == NULL) {
		throw CustomException("git diff | sha1sum failed");
	}
	char delta_hash[41] = {};
	fread(delta_hash, sizeof(char), 40, f);
	pclose(f);

	return std::string(delta_hash);
}

static std::string git_remote(const std::string & gdir, const std::string & remote)
{
	std::string cmd = "cd " + gdir + " && git config --local --get remote." + remote + ".url";
	FILE *f = popen(cmd.c_str(), "r");
	if(f == NULL) {
		throw CustomException("git config --local --get remote. .url failed");
	}
	char output[1025] = {};
	fread(output, sizeof(char), 1024, f);
	pclose(f);

	return std::string(output);
}

GitDirExtractionUnit::GitDirExtractionUnit(const std::string & git_dir,
					   const std::string & to_dir)
{
	this->uri = git_dir;
	this->hash = git_hash(this->uri);
	this->toDir = to_dir;
}

GitDirExtractionUnit::GitDirExtractionUnit()
{
}

bool GitDirExtractionUnit::isDirty()
{
	if(!directory_exists(this->localPath())) {
		/* If the source directory doesn't exist, then it can't be dirty */
		return false;
	}

	std::string cmd = string_format("cd %s && git diff --quiet HEAD",
					this->localPath().c_str());
	int res = std::system(cmd.c_str());
	return (res != 0);
}

std::string GitDirExtractionUnit::dirtyHash()
{
	return git_diff_hash(this->localPath());
}

GitExtractionUnit::GitExtractionUnit(const std::string & remote, const std::string & local,
				     std::string refspec, Package * P)
{
	this->uri = remote;
	this->local = P->getWorld()->getWorkingDir() + "/source/" + local;
	this->refspec = refspec;
	this->P = P;
	this->fetched = false;
}

bool GitExtractionUnit::updateOrigin()
{
	std::string location = this->uri;
	std::string source_dir = this->local;
	std::string remote_url = git_remote(source_dir, "origin");

	if(remote_url != location) {
		PackageCmd pc(source_dir.c_str(), "git");
		pc.addArg("remote");
		// If the remote doesn't exist, add it
		if(remote_url == "") {
			pc.addArg("add");
		} else {
			pc.addArg("set-url");
		}
		pc.addArg("origin");
		pc.addArg(location.c_str());
		if(!pc.Run(this->P)) {
			throw CustomException("Failed: git remote set-url origin");
		}

		pc = PackageCmd(source_dir.c_str(), "git");
		pc.addArg("fetch");
		pc.addArg("origin");
		pc.addArg("--tags");
		if(!pc.Run(this->P)) {
			throw CustomException("Failed: git fetch origin --tags");
		}
	}

	return true;
}

bool GitExtractionUnit::fetch(BuildDir * d)
{
	std::string location = this->uri;
	std::string source_dir = this->local;
	std::string cwd = d->getWorld()->getWorkingDir();

	bool exists = directory_exists(source_dir);

	PackageCmd pc(exists ? source_dir : cwd, "git");

	if(exists) {
		/* Update the origin */
		this->updateOrigin();
		/* Check if the commit is already present */
		std::string cmd =
		    "cd " + source_dir + "; git cat-file -e " + this->refspec +
		    " 2>/dev/null";
		if(std::system(cmd.c_str()) != 0) {
			/* If not, fetch everything from origin */
			pc.addArg("fetch");
			pc.addArg("origin");
			pc.addArg("--tags");
			if(!pc.Run(this->P)) {
				throw CustomException("Failed: git fetch origin --tags");
			}
		}
	} else {
		pc.addArg("clone");
		pc.addArg("-n");
		pc.addArg(location.c_str());
		pc.addArg(source_dir.c_str());
		if(!pc.Run(this->P))
			throw CustomException("Failed to git clone");
	}

	if(this->refspec.compare("HEAD") == 0) {
		// Don't touch it
	} else {
		std::string cmd =
		    "cd " + source_dir +
		    "; git show-ref --quiet --verify -- refs/heads/" + this->refspec;
		if(std::system(cmd.c_str()) == 0) {
			std::string head_hash = git_hash_ref(source_dir, "HEAD");
			std::string branch_hash = git_hash_ref(source_dir, this->refspec);
			if(head_hash != branch_hash) {
				throw CustomException("Asked to use branch: " +
						      this->refspec + ", but " +
						      source_dir +
						      " is off somewhere else");
			}
		} else {
			pc = PackageCmd(source_dir.c_str(), "git");
			// switch to refspec
			pc.addArg("checkout");
			pc.addArg("-q");
			pc.addArg("--detach");
			pc.addArg(this->refspec.c_str());
			if(!pc.Run(this->P))
				throw CustomException("Failed to checkout");
		}
	}
	bool res = true;

	std::string hash = git_hash(source_dir);

	if(!this->hash.empty()) {
		if(this->hash != hash) {
			log(this->P,
			    "Hash mismatch for %s\n(committed to %s, providing %s)\n",
			    this->uri.c_str(), this->hash.c_str(), hash.c_str());
			res = false;
		}
	} else {
		this->hash = hash;
	}

	this->fetched = res;

	return res;
}

std::string GitExtractionUnit::HASH()
{
	if(refspec_is_commitid(this->refspec)) {
		this->hash = std::string(this->refspec);
	} else {
		std::string digest_name = string_format("%s#%s", this->uri.c_str(),
							this->refspec.c_str());
		/* Check if the package contains pre-computed hashes */
		std::string Hash = P->getFileHash(digest_name);
		if(Hash.empty()) {
			this->fetch(P->builddir());
		} else {
			this->hash = Hash;
		}
	}
	return this->hash;
}

bool GitExtractionUnit::extract(Package * P, BuildDir * bd)
{
	// make sure it has been fetched
	if(!this->fetched) {
		if(!this->fetch(bd)) {
			return false;
		}
	}
	// copy to work dir
	PackageCmd pc(bd->getPath(), "cp");
	pc.addArg("-dpRuf");
	pc.addArg(this->localPath());
	pc.addArg(".");
	if(!pc.Run(P))
		throw CustomException("Failed to checkout");

	return true;
}

bool LinkGitDirExtractionUnit::extract(Package * P, BuildDir * bd)
{
	PackageCmd pc(bd->getPath(), "ln");

	pc.addArg("-sfT");

	if(this->uri.at(0) == '.') {
		std::string arg = P->getWorld()->getWorkingDir() + "/" + this->uri;
		pc.addArg(arg);
	} else {
		pc.addArg(this->uri);
	}
	pc.addArg(this->toDir);

	if(!pc.Run(P)) {
		throw CustomException("Operation failed");
	}

	return true;
}

bool CopyGitDirExtractionUnit::extract(Package * P, BuildDir * bd)
{
	PackageCmd pc(bd->getPath(), "cp");
	pc.addArg("-dpRuf");

	if(this->uri.at(0) == '.') {
		std::string arg = P->getWorld()->getWorkingDir() + "/" + this->uri;
		pc.addArg(arg);
	} else {
		pc.addArg(this->uri);
	}
	pc.addArg(this->toDir);

	if(!pc.Run(P)) {
		throw CustomException("Operation failed");
	}

	return true;
}
<|endoftext|>


<commit_before>#include "spatial_organization/binary_tree_element.h"

#include <stack>
#include <sstream>

#include "string_util.h"
#include "physics/physical_node.h"

namespace bdm {
namespace spatial_organization {

template<class T>
BinaryTreeElement<T>* BinaryTreeElement<T>::generateTreeHead() {
  return new TreeHead<T>();
}

template<class T>
BinaryTreeElement<T>::BinaryTreeElement(SpaceNode<T>* content)
    : content_ { content },
      smaller_ { nullptr },
      bigger_ { nullptr } {
  if (content_ != nullptr) {
    content_id_ = getHash(content);
  } else {
    content_id_ = -1;
  }
}

template<class T>
BinaryTreeElement<T>::~BinaryTreeElement() {
  delete smaller_;
  delete bigger_;
}

template<class T>
bool BinaryTreeElement<T>::contains(SpaceNode<T>* content) const {
  return contains(getHash(content), content);
}

template<class T>
void BinaryTreeElement<T>::insert(SpaceNode<T>* content) {
  if (content != nullptr) {
    insert(new BinaryTreeElement<T>(content));
  }
}

template<class T>
void BinaryTreeElement<T>::remove(SpaceNode<T>* content, BinaryTreeElement* parent) {
  remove(getHash(content), content, parent);
}

template<class T>
std::string BinaryTreeElement<T>::toString() const {
  stringstream str_stream;
  str_stream << StringUtil::toStr(smaller_);
  str_stream << ", ";
  str_stream << StringUtil::toStr(content_);
  str_stream << ", ";
  str_stream << StringUtil::toStr(bigger_);
  return str_stream.str();
}

template<class T>
int BinaryTreeElement<T>::getHash(SpaceNode<T>* content) const {
  uint64_t id = content_->getId();
  uint64_t c = 7481;
  return (id * c) % 74317;
}

template<class T>
bool BinaryTreeElement<T>::contains(int id, SpaceNode<T>* content) const {
  return contains(getHash(content), content);
}

template<class T>
void BinaryTreeElement<T>::insert(BinaryTreeElement* element) {
  if (content_id_ == element->content_id_ && content_ == element->content_) {
    delete element;
    return;
  } else if ((content_id_ >= element->content_id_)) {
    if ((smaller_ != nullptr)) {
      smaller_->insert(element);
    } else {
      smaller_ = element;
    }
  } else if (content_id_ < element->content_id_) {
    if (bigger_ != nullptr) {
      bigger_->insert(element);
    } else {
      bigger_ = element;
    }
  }
}

template<class T>
void BinaryTreeElement<T>::remove(int id, SpaceNode<T>* content, BinaryTreeElement* parent) {
  if ((content_id_ == id) && (content_ == content)) {
    if ((smaller_ == nullptr) && (bigger_ == nullptr)) {
      parent->changeLink(this, nullptr);
      //use of randomization in the next if showed no influence on the simulation outcome
    } else if ((smaller_ != nullptr) || (bigger_ == nullptr)) {
      parent->changeLink(this, smaller_);
      if (bigger_ != nullptr) {
        smaller_->insert(bigger_);
      }
    } else {
      parent->changeLink(this, bigger_);
      if (smaller_ != nullptr) {
        bigger_->insert(smaller_);
      }
    }
  } else {
    if ((content_id_ >= id) && (smaller_ != nullptr)) {
      smaller_->remove(id, content, this);

    } else if ((content_id_ < id) && (bigger_ != nullptr)) {
      bigger_->remove(id, content, this);
    }
  }
}

template<class T>
void BinaryTreeElement<T>::changeLink(BinaryTreeElement* old_el, BinaryTreeElement* new_el) {
  if (smaller_ == old_el) {
    smaller_ = new_el;
  } else if (bigger_ == old_el) {
    bigger_ = new_el;
  }
}

template<class T>
std::vector<SpaceNode<T>*> BinaryTreeElement<T>::inOrderTraversal() const {
  std::vector<SpaceNode<T>*> traversal;
  std::stack<const BinaryTreeElement<T>*> stack;
  const BinaryTreeElement<T>* dummy = this;
  while (dummy != nullptr) {
    stack.push(dummy);
    dummy = dummy->smaller_;
  }

  while (!stack.empty()) {
    dummy = stack.top();
    stack.pop();
    auto it = dummy->bigger_;
    while (it != nullptr) {
      stack.push(it);
      it = it->smaller_;
    }
    traversal.push_back(dummy->content_);
  }
  return traversal;
}

//-------------------------------------------------------------------------------------------------
// TreeHead

template<class T>
TreeHead<T>::TreeHead()
    : BinaryTreeElement<T>(nullptr) {

}

template<class T>
bool TreeHead<T>::contains(SpaceNode<T>* content) const {
  return BinaryTreeElement < T > ::bigger_ != nullptr ? BinaryTreeElement < T > ::bigger_->contains(content) : false;
}

template<class T>
void TreeHead<T>::insert(SpaceNode<T>* content) {
  if (BinaryTreeElement < T > ::bigger_ != nullptr) {
    BinaryTreeElement < T > ::bigger_->insert(content);
  } else {
    BinaryTreeElement < T > ::bigger_ = new BinaryTreeElement<T>(content);
  }
}

template<class T>
void TreeHead<T>::remove(SpaceNode<T>* content, BinaryTreeElement<T>* parent) {
  if (BinaryTreeElement < T > ::bigger_ != nullptr) {
    BinaryTreeElement < T > ::bigger_->remove(content, this);
  }
}

template<class T>
std::vector<SpaceNode<T>*> TreeHead<T>::inOrderTraversal() const {
  if (BinaryTreeElement < T > ::bigger_ != nullptr) {
    return BinaryTreeElement < T > ::bigger_->inOrderTraversal();
  }
  return std::vector<SpaceNode<T>*>();
}

template class BinaryTreeElement<bdm::physics::PhysicalNode> ;

}  // namespace spatial_organization
}  // namespace bdm
<commit_msg>Fix copy paste error in BinaryTreeElement::contains method - fixes BIOD-5<commit_after>#include "spatial_organization/binary_tree_element.h"

#include <stack>
#include <sstream>

#include "string_util.h"
#include "physics/physical_node.h"

namespace bdm {
namespace spatial_organization {

template<class T>
BinaryTreeElement<T>* BinaryTreeElement<T>::generateTreeHead() {
  return new TreeHead<T>();
}

template<class T>
BinaryTreeElement<T>::BinaryTreeElement(SpaceNode<T>* content)
    : content_ { content },
      smaller_ { nullptr },
      bigger_ { nullptr } {
  if (content_ != nullptr) {
    content_id_ = getHash(content);
  } else {
    content_id_ = -1;
  }
}

template<class T>
BinaryTreeElement<T>::~BinaryTreeElement() {
  delete smaller_;
  delete bigger_;
}

template<class T>
bool BinaryTreeElement<T>::contains(SpaceNode<T>* content) const {
  return contains(getHash(content), content);
}

template<class T>
void BinaryTreeElement<T>::insert(SpaceNode<T>* content) {
  if (content != nullptr) {
    insert(new BinaryTreeElement<T>(content));
  }
}

template<class T>
void BinaryTreeElement<T>::remove(SpaceNode<T>* content, BinaryTreeElement* parent) {
  remove(getHash(content), content, parent);
}

template<class T>
std::string BinaryTreeElement<T>::toString() const {
  stringstream str_stream;
  str_stream << StringUtil::toStr(smaller_);
  str_stream << ", ";
  str_stream << StringUtil::toStr(content_);
  str_stream << ", ";
  str_stream << StringUtil::toStr(bigger_);
  return str_stream.str();
}

template<class T>
int BinaryTreeElement<T>::getHash(SpaceNode<T>* content) const {
  uint64_t id = content_->getId();
  uint64_t c = 7481;
  return (id * c) % 74317;
}

template<class T>
bool BinaryTreeElement<T>::contains(int id, SpaceNode<T>* content) const {
  if (content_ == content) {
    return true;
  } else {
    if (content_id_ >= id && smaller_ != nullptr) {
      return smaller_->contains(id, content);
    } else if (content_id_ < id && bigger_ != nullptr) {
      return bigger_->contains(id, content);
    }else {
      return false;
    }
  }
}

template<class T>
void BinaryTreeElement<T>::insert(BinaryTreeElement* element) {
  if (content_id_ == element->content_id_ && content_ == element->content_) {
    delete element;
    return;
  } else if ((content_id_ >= element->content_id_)) {
    if ((smaller_ != nullptr)) {
      smaller_->insert(element);
    } else {
      smaller_ = element;
    }
  } else if (content_id_ < element->content_id_) {
    if (bigger_ != nullptr) {
      bigger_->insert(element);
    } else {
      bigger_ = element;
    }
  }
}

template<class T>
void BinaryTreeElement<T>::remove(int id, SpaceNode<T>* content, BinaryTreeElement* parent) {
  if ((content_id_ == id) && (content_ == content)) {
    if ((smaller_ == nullptr) && (bigger_ == nullptr)) {
      parent->changeLink(this, nullptr);
      //use of randomization in the next if showed no influence on the simulation outcome
    } else if ((smaller_ != nullptr) || (bigger_ == nullptr)) {
      parent->changeLink(this, smaller_);
      if (bigger_ != nullptr) {
        smaller_->insert(bigger_);
      }
    } else {
      parent->changeLink(this, bigger_);
      if (smaller_ != nullptr) {
        bigger_->insert(smaller_);
      }
    }
  } else {
    if ((content_id_ >= id) && (smaller_ != nullptr)) {
      smaller_->remove(id, content, this);

    } else if ((content_id_ < id) && (bigger_ != nullptr)) {
      bigger_->remove(id, content, this);
    }
  }
}

template<class T>
void BinaryTreeElement<T>::changeLink(BinaryTreeElement* old_el, BinaryTreeElement* new_el) {
  if (smaller_ == old_el) {
    smaller_ = new_el;
  } else if (bigger_ == old_el) {
    bigger_ = new_el;
  }
}

template<class T>
std::vector<SpaceNode<T>*> BinaryTreeElement<T>::inOrderTraversal() const {
  std::vector<SpaceNode<T>*> traversal;
  std::stack<const BinaryTreeElement<T>*> stack;
  const BinaryTreeElement<T>* dummy = this;
  while (dummy != nullptr) {
    stack.push(dummy);
    dummy = dummy->smaller_;
  }

  while (!stack.empty()) {
    dummy = stack.top();
    stack.pop();
    auto it = dummy->bigger_;
    while (it != nullptr) {
      stack.push(it);
      it = it->smaller_;
    }
    traversal.push_back(dummy->content_);
  }
  return traversal;
}

//-------------------------------------------------------------------------------------------------
// TreeHead

template<class T>
TreeHead<T>::TreeHead()
    : BinaryTreeElement<T>(nullptr) {

}

template<class T>
bool TreeHead<T>::contains(SpaceNode<T>* content) const {
  return BinaryTreeElement < T > ::bigger_ != nullptr ? BinaryTreeElement < T > ::bigger_->contains(content) : false;
}

template<class T>
void TreeHead<T>::insert(SpaceNode<T>* content) {
  if (BinaryTreeElement < T > ::bigger_ != nullptr) {
    BinaryTreeElement < T > ::bigger_->insert(content);
  } else {
    BinaryTreeElement < T > ::bigger_ = new BinaryTreeElement<T>(content);
  }
}

template<class T>
void TreeHead<T>::remove(SpaceNode<T>* content, BinaryTreeElement<T>* parent) {
  if (BinaryTreeElement < T > ::bigger_ != nullptr) {
    BinaryTreeElement < T > ::bigger_->remove(content, this);
  }
}

template<class T>
std::vector<SpaceNode<T>*> TreeHead<T>::inOrderTraversal() const {
  if (BinaryTreeElement < T > ::bigger_ != nullptr) {
    return BinaryTreeElement < T > ::bigger_->inOrderTraversal();
  }
  return std::vector<SpaceNode<T>*>();
}

template class BinaryTreeElement<bdm::physics::PhysicalNode> ;

}  // namespace spatial_organization
}  // namespace bdm
<|endoftext|>