<commit_before>/**
* @file Sort_test.cpp
* @brief Unit tests for the Sort class.
* @author Dominique LaSalle <dominique@solidlake.com>
* Copyright 2018
* @version 1
* @date 2018-08-23
*/

#include "Sort.hpp"
#include "UnitTest.hpp"

#include <random>

namespace sl
{

UNITTEST(Sort, FixedKeys)
{
  std::vector<int> keys{0,5,2,3,4,1,1,3};

  std::unique_ptr<size_t[]> perm = Sort::fixedKeys<int, size_t>(keys.data(), \
      keys.size());

  testEqual(perm[0], 0UL);
  testEqual(perm[1], 5UL);
  testEqual(perm[2], 6UL);
  testEqual(perm[3], 2UL);
  testEqual(perm[4], 3UL);
  testEqual(perm[5], 7UL);
  testEqual(perm[6], 4UL);
}

UNITTEST(Sort, FixedKeysRandom)
{
  std::vector<int> keys{0,1,0,2,1,0};

  std::mt19937 rng(0);

  std::unique_ptr<size_t[]> perm1 = Sort::fixedKeysRandom<int, size_t>(keys.data(), \
      keys.size(), rng);
  std::unique_ptr<size_t[]> perm2 = Sort::fixedKeysRandom<int, size_t>(keys.data(), \
      keys.size(), rng);

  // check order
  testLessOrEqual(keys[perm1[0]], keys[perm1[1]]);
  testLessOrEqual(keys[perm1[1]], keys[perm1[2]]);
  testLessOrEqual(keys[perm1[2]], keys[perm1[3]]);
  testLessOrEqual(keys[perm1[3]], keys[perm1[4]]);
  testLessOrEqual(keys[perm1[4]], keys[perm1[5]]);

  testLessOrEqual(keys[perm2[0]], keys[perm2[1]]);
  testLessOrEqual(keys[perm2[1]], keys[perm2[2]]);
  testLessOrEqual(keys[perm2[2]], keys[perm2[3]]);
  testLessOrEqual(keys[perm2[3]], keys[perm2[4]]);
  testLessOrEqual(keys[perm2[4]], keys[perm2[5]]);

  // make sure orders are different
  bool different = false;
  for (size_t i = 0; i < keys.size(); ++i) {
    if (perm1[i] != perm2[i]) {
      different = true;
    }
  }
  testTrue(different);
}

}
<commit_msg>Increase array size<commit_after>/**
* @file Sort_test.cpp
* @brief Unit tests for the Sort class.
* @author Dominique LaSalle <dominique@solidlake.com>
* Copyright 2018
* @version 1
* @date 2018-08-23
*/

#include "Sort.hpp"
#include "UnitTest.hpp"

#include <random>

namespace sl
{

UNITTEST(Sort, FixedKeys)
{
  std::vector<int> keys{0,5,2,3,4,1,1,3};

  std::unique_ptr<size_t[]> perm = Sort::fixedKeys<int, size_t>(keys.data(), \
      keys.size());

  testEqual(perm[0], 0UL);
  testEqual(perm[1], 5UL);
  testEqual(perm[2], 6UL);
  testEqual(perm[3], 2UL);
  testEqual(perm[4], 3UL);
  testEqual(perm[5], 7UL);
  testEqual(perm[6], 4UL);
}

UNITTEST(Sort, FixedKeysRandom)
{
  std::vector<int> keys{0,1,0,0,2,1,0,1,2,2,1,0,1,2,2,1,1,1};

  std::mt19937 rng(0);

  std::unique_ptr<size_t[]> perm1 = Sort::fixedKeysRandom<int, size_t>( \
      keys.data(), keys.size(), rng);
  std::unique_ptr<size_t[]> perm2 = Sort::fixedKeysRandom<int, size_t>( \
      keys.data(), keys.size(), rng);

  // check order
  for (size_t i = 0; i+1 < keys.size(); ++i) {
    testLessOrEqual(keys[perm1[i]], keys[perm1[i+1]]);
    testLessOrEqual(keys[perm2[i]], keys[perm2[i+1]]);
  }

  // make sure orders are different
  int different = 0;
  for (size_t i = 0; i < keys.size(); ++i) {
    if (perm1[i] != perm2[i]) {
      ++different;
    }
  }
  testGreater(different, 0);
}

}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "meegoaccelerometer.h"
#include "meegoals.h"
#include "meegocompass.h"
#include "meegomagnetometer.h"
#include "meegoorientationsensor.h"
#include "meegoproximitysensor.h"
#include "meegorotationsensor.h"
#include "meegotapsensor.h"
#include "meegogyroscope.h"
#include "meegolightsensor.h"

#include <qlightsensor.h>
#include <qsensorplugin.h>
#include <qsensorbackend.h>
#include <qsensormanager.h>
#include <QDebug>

class meegoSensorPlugin : public QObject, public QSensorPluginInterface, public QSensorBackendFactory
{
    Q_OBJECT
    Q_INTERFACES(QtMobility::QSensorPluginInterface)
public:

    void registerSensors()
    {
        // if no default - no support either, uses Sensors.conf
        const char* const MEEGO = "meego";
        if (QString(QSensor::defaultSensorForType("QAccelerometer")).startsWith(MEEGO))
            QSensorManager::registerBackend(QAccelerometer::type, meegoaccelerometer::id, this);
        if (QSensor::defaultSensorForType("QAmbientLightSensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QAmbientLightSensor::type, meegoals::id, this);
        if (QSensor::defaultSensorForType("QCompass").startsWith(MEEGO))
            QSensorManager::registerBackend(QCompass::type, meegocompass::id, this);
        if (QSensor::defaultSensorForType("QMagnetometer").startsWith(MEEGO))
            QSensorManager::registerBackend(QMagnetometer::type, meegomagnetometer::id, this);
        if (QSensor::defaultSensorForType("QOrientationSensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QOrientationSensor::type, meegoorientationsensor::id, this);
        if (QSensor::defaultSensorForType("QProximitySensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QProximitySensor::type, meegoproximitysensor::id, this);
        if (QSensor::defaultSensorForType("QRotationSensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QRotationSensor::type, meegorotationsensor::id, this);
        if (QSensor::defaultSensorForType("QTapSensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QTapSensor::type, meegotapsensor::id, this);
        if (QSensor::defaultSensorForType("QGyroscope").startsWith(MEEGO))
            QSensorManager::registerBackend(QGyroscope::type, meegogyroscope::id, this);
        if (QSensor::defaultSensorForType("QLightSensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QLightSensor::type, meegolightsensor::id, this);
        qDebug() << "Loaded the MeeGo sensor plugin";
    }

    QSensorBackend *createBackend(QSensor *sensor)
    {
        if (sensor->identifier() == meegoaccelerometer::id)
            return new meegoaccelerometer(sensor);
        else if (sensor->identifier() == meegoals::id)
            return new meegoals(sensor);
        else if (sensor->identifier() == meegocompass::id)
            return new meegocompass(sensor);
        else if (sensor->identifier() == meegomagnetometer::id)
            return new meegomagnetometer(sensor);
        else if (sensor->identifier() == meegoorientationsensor::id)
            return new meegoorientationsensor(sensor);
        else if (sensor->identifier() == meegoproximitysensor::id)
            return new meegoproximitysensor(sensor);
        else if (sensor->identifier() == meegorotationsensor::id)
            return new meegorotationsensor(sensor);
        else if (sensor->identifier() == meegotapsensor::id)
            return new meegotapsensor(sensor);
        else if (sensor->identifier() == meegogyroscope::id)
            return new meegogyroscope(sensor);
        else if (sensor->identifier() == meegolightsensor::id)
            return new meegolightsensor(sensor);
        return 0;
    }
};

Q_EXPORT_PLUGIN2(libsensors_meego, meegoSensorPlugin)

#include "main.moc"
<commit_msg>default to show support: still failing<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "meegoaccelerometer.h"
#include "meegoals.h"
#include "meegocompass.h"
#include "meegomagnetometer.h"
#include "meegoorientationsensor.h"
#include "meegoproximitysensor.h"
#include "meegorotationsensor.h"
#include "meegotapsensor.h"
#include "meegogyroscope.h"
#include "meegolightsensor.h"

#include <qsensorplugin.h>
#include <qsensorbackend.h>
#include <qsensormanager.h>
#include <QDebug>

class meegoSensorPlugin : public QObject, public QSensorPluginInterface, public QSensorBackendFactory
{
    Q_OBJECT
    Q_INTERFACES(QtMobility::QSensorPluginInterface)
public:

    void registerSensors()
    {
        // if no default - no support either, uses Sensors.conf
        const char* const MEEGO = "meego";
//        if (QString(QSensor::defaultSensorForType("QAccelerometer")).startsWith(MEEGO))
            QSensorManager::registerBackend(QAccelerometer::type, meegoaccelerometer::id, this);
//        if (QSensor::defaultSensorForType("QAmbientLightSensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QAmbientLightSensor::type, meegoals::id, this);
//        if (QSensor::defaultSensorForType("QCompass").startsWith(MEEGO))
            QSensorManager::registerBackend(QCompass::type, meegocompass::id, this);
//        if (QSensor::defaultSensorForType("QMagnetometer").startsWith(MEEGO))
            QSensorManager::registerBackend(QMagnetometer::type, meegomagnetometer::id, this);
//        if (QSensor::defaultSensorForType("QOrientationSensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QOrientationSensor::type, meegoorientationsensor::id, this);
//        if (QSensor::defaultSensorForType("QProximitySensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QProximitySensor::type, meegoproximitysensor::id, this);
//        if (QSensor::defaultSensorForType("QRotationSensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QRotationSensor::type, meegorotationsensor::id, this);
//        if (QSensor::defaultSensorForType("QTapSensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QTapSensor::type, meegotapsensor::id, this);
//        if (QSensor::defaultSensorForType("QGyroscope").startsWith(MEEGO))
            QSensorManager::registerBackend(QGyroscope::type, meegogyroscope::id, this);
//        if (QSensor::defaultSensorForType("QLightSensor").startsWith(MEEGO))
            QSensorManager::registerBackend(QLightSensor::type, meegolightsensor::id, this);
        qDebug() << "Loaded the MeeGo sensor plugin";
    }

    QSensorBackend *createBackend(QSensor *sensor)
    {
        if (sensor->identifier() == meegoaccelerometer::id)
            return new meegoaccelerometer(sensor);
        else if (sensor->identifier() == meegoals::id)
            return new meegoals(sensor);
        else if (sensor->identifier() == meegocompass::id)
            return new meegocompass(sensor);
        else if (sensor->identifier() == meegomagnetometer::id)
            return new meegomagnetometer(sensor);
        else if (sensor->identifier() == meegoorientationsensor::id)
            return new meegoorientationsensor(sensor);
        else if (sensor->identifier() == meegoproximitysensor::id)
            return new meegoproximitysensor(sensor);
        else if (sensor->identifier() == meegorotationsensor::id)
            return new meegorotationsensor(sensor);
        else if (sensor->identifier() == meegotapsensor::id)
            return new meegotapsensor(sensor);
        else if (sensor->identifier() == meegogyroscope::id)
            return new meegogyroscope(sensor);
        else if (sensor->identifier() == meegolightsensor::id)
            return new meegolightsensor(sensor);
        return 0;
    }
};

Q_EXPORT_PLUGIN2(libsensors_meego, meegoSensorPlugin)

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


<commit_before><commit_msg>Add Latin 2015 A<commit_after><|endoftext|>


<commit_before>#include <elevator/scheduler.h>
#include <elevator/restartwrapper.h>

namespace elevator {

Scheduler::Scheduler( int localId, HeartBeat &hb, BasicDriverInfo info,
        ConcurrentQueue< StateChange > &stateUpdateIn,
        ConcurrentQueue< StateChange > &stateUpdateOut,
        ConcurrentQueue< Command > &commandsToRemote,
        ConcurrentQueue< Command > &commandsToLocal ) :
    _localElevId( localId ),
    _heartbeat( hb ),
    _bounds( info ),
    _stateUpdateIn( stateUpdateIn ),
    _stateUpdateOut( stateUpdateOut ),
    _commandsToRemote( commandsToRemote ),
    _commandsToLocal( commandsToLocal ),
    _terminate( false )
{ }

Scheduler::~Scheduler() {
    if ( _thr.joinable() ) {
        _terminate = true;
        _thr.join();
    }
}

void Scheduler::run() {
    _thr = std::thread( restartWrapper( &Scheduler::_runLocal ), this );
}

const char *showChange( ChangeType );

void Scheduler::_forwardToTargets( Command comm ) {
    if ( comm.targetElevatorId == Command::ANY_ID || comm.targetElevatorId == _localElevId )
        _commandsToLocal.enqueue( comm );
    if ( comm.targetElevatorId != _localElevId )
        _commandsToRemote.enqueue( comm );
}

void Scheduler::_handleButtonPress( ButtonType type, int floor ) {
    // first setup lights
    Command lights{ type == ButtonType::CallUp
                      ? CommandType::TurnOnLightUp : CommandType::TurnOnLightDown,
                    Command::ANY_ID, floor };
    _forwardToTargets( lights );

    // now find optimal elevator
    int minDistance = INT_MAX;
    int minId = INT_MIN;

    for ( auto &statepair : _globalState.elevators() ) {
        const ElevatorState &state = statepair.second;

        int dist = std::abs( state.lastFloor - floor );

        if ( state.stopped )
            dist += 10 * (_bounds.maxFloor() - _bounds.minFloor()); // penalisation

        if (    ( state.direction == Direction::Up
                        && ( (type == ButtonType::CallUp && floor > state.lastFloor )
                            || floor == _bounds.maxFloor() ) )
            ||
                ( state.direction == Direction::Down
                        && ( (type == ButtonType::CallDown && floor < state.lastFloor )
                            || floor == _bounds.minFloor() ) )
           )
            dist += _bounds.maxFloor() - _bounds.minFloor() + 1; // busy penalisation
        else
            // as a last resort we can schedule floor even to elevator which is
            // running in different direction
            dist += 2 * (_bounds.maxFloor() - _bounds.minFloor() + 1); // penalisation

        if ( dist < minDistance ) {
            minDistance = dist;
            minId = state.id;
        }
    }
    assert_leq( 0, minId, "no minimal distance found" );

    Command comm{ type == ButtonType::CallUp
                      ? CommandType::CallToFloorAndGoUp
                      : CommandType::CallToFloorAndGoDown,
                  minId, floor };
    _forwardToTargets( comm );
}

void Scheduler::_runLocal() {
    while ( !_terminate.load( std::memory_order::memory_order_relaxed ) ) {
        auto maybeUpdate = _stateUpdateIn.timeoutDequeue( _heartbeat.threshold() / 2 );
        if ( !maybeUpdate.isNothing() ) {
            auto update = maybeUpdate.value();
            _globalState.update( update.state );
            std::cerr << "state update: { id = " << update.state.id
                << ", timestamp = " << update.state.timestamp
                << ", changeType = " << showChange( update.changeType )
                << ", changeFloor = " << update.changeFloor << " }" << std::endl;

            if ( update.state.id == _localElevId ) {
                _stateUpdateOut( update ); // propagate update

                // each elevator is responsible for scheduling commnads from its hardware
                switch ( update.changeType ) {
                    case ChangeType::None:
                    case ChangeType::KeepAlive:
                    case ChangeType::OtherChange:
                        continue;
                    case ChangeType::ButtonUpPressed:
                        _handleButtonPress( ButtonType::CallUp, update.changeFloor );
                        break;
                    case ChangeType::ButtonDownPressed:
                        _handleButtonPress( ButtonType::CallDown, update.changeFloor );
                        break;
                }
            }
        }

        _heartbeat.beat();
    }
}

const char *showChange( ChangeType t ) {
#define show( X ) case ChangeType::X: return #X
    switch ( t ) {
        show( None );
        show( KeepAlive );

        show( InsideButtonPresed );
        show( ButtonDownPressed );
        show( ButtonUpPressed );

        show( Served );
        show( ServedUp );
        show( ServedDown );

        show( OtherChange );
    }
#undef show
    return "<<unknown>>";
}

}
<commit_msg>scheduler: Fix compilation error.<commit_after>#include <elevator/scheduler.h>
#include <elevator/restartwrapper.h>

namespace elevator {

Scheduler::Scheduler( int localId, HeartBeat &hb, BasicDriverInfo info,
        ConcurrentQueue< StateChange > &stateUpdateIn,
        ConcurrentQueue< StateChange > &stateUpdateOut,
        ConcurrentQueue< Command > &commandsToRemote,
        ConcurrentQueue< Command > &commandsToLocal ) :
    _localElevId( localId ),
    _heartbeat( hb ),
    _bounds( info ),
    _stateUpdateIn( stateUpdateIn ),
    _stateUpdateOut( stateUpdateOut ),
    _commandsToRemote( commandsToRemote ),
    _commandsToLocal( commandsToLocal ),
    _terminate( false )
{ }

Scheduler::~Scheduler() {
    if ( _thr.joinable() ) {
        _terminate = true;
        _thr.join();
    }
}

void Scheduler::run() {
    _thr = std::thread( restartWrapper( &Scheduler::_runLocal ), this );
}

const char *showChange( ChangeType );

void Scheduler::_forwardToTargets( Command comm ) {
    if ( comm.targetElevatorId == Command::ANY_ID || comm.targetElevatorId == _localElevId )
        _commandsToLocal.enqueue( comm );
    if ( comm.targetElevatorId != _localElevId )
        _commandsToRemote.enqueue( comm );
}

void Scheduler::_handleButtonPress( ButtonType type, int floor ) {
    // first setup lights
    Command lights{ type == ButtonType::CallUp
                      ? CommandType::TurnOnLightUp : CommandType::TurnOnLightDown,
                    Command::ANY_ID, floor };
    _forwardToTargets( lights );

    // now find optimal elevator
    int minDistance = INT_MAX;
    int minId = INT_MIN;

    for ( auto &statepair : _globalState.elevators() ) {
        const ElevatorState &state = statepair.second;

        int dist = std::abs( state.lastFloor - floor );

        if ( state.stopped )
            dist += 10 * (_bounds.maxFloor() - _bounds.minFloor()); // penalisation

        if (    ( state.direction == Direction::Up
                        && ( (type == ButtonType::CallUp && floor > state.lastFloor )
                            || floor == _bounds.maxFloor() ) )
            ||
                ( state.direction == Direction::Down
                        && ( (type == ButtonType::CallDown && floor < state.lastFloor )
                            || floor == _bounds.minFloor() ) )
           )
            dist += _bounds.maxFloor() - _bounds.minFloor() + 1; // busy penalisation
        else
            // as a last resort we can schedule floor even to elevator which is
            // running in different direction
            dist += 2 * (_bounds.maxFloor() - _bounds.minFloor() + 1); // penalisation

        if ( dist < minDistance ) {
            minDistance = dist;
            minId = state.id;
        }
    }
    assert_leq( 0, minId, "no minimal distance found" );

    Command comm{ type == ButtonType::CallUp
                      ? CommandType::CallToFloorAndGoUp
                      : CommandType::CallToFloorAndGoDown,
                  minId, floor };
    _forwardToTargets( comm );
}

void Scheduler::_runLocal() {
    while ( !_terminate.load( std::memory_order::memory_order_relaxed ) ) {
        auto maybeUpdate = _stateUpdateIn.timeoutDequeue( _heartbeat.threshold() / 2 );
        if ( !maybeUpdate.isNothing() ) {
            auto update = maybeUpdate.value();
            _globalState.update( update.state );
            std::cerr << "state update: { id = " << update.state.id
                << ", timestamp = " << update.state.timestamp
                << ", changeType = " << showChange( update.changeType )
                << ", changeFloor = " << update.changeFloor << " }" << std::endl;

            if ( update.state.id == _localElevId ) {
                _stateUpdateOut.enqueue( update ); // propagate update

                // each elevator is responsible for scheduling commnads from its hardware
                switch ( update.changeType ) {
                    case ChangeType::None:
                    case ChangeType::KeepAlive:
                    case ChangeType::OtherChange:
                        continue;
                    case ChangeType::ButtonUpPressed:
                        _handleButtonPress( ButtonType::CallUp, update.changeFloor );
                        break;
                    case ChangeType::ButtonDownPressed:
                        _handleButtonPress( ButtonType::CallDown, update.changeFloor );
                        break;
                }
            }
        }

        _heartbeat.beat();
    }
}

const char *showChange( ChangeType t ) {
#define show( X ) case ChangeType::X: return #X
    switch ( t ) {
        show( None );
        show( KeepAlive );

        show( InsideButtonPresed );
        show( ButtonDownPressed );
        show( ButtonUpPressed );

        show( Served );
        show( ServedUp );
        show( ServedDown );

        show( OtherChange );
    }
#undef show
    return "<<unknown>>";
}

}
<|endoftext|>


<commit_before>/*
 * This file is part of the libsumo - a reverse-engineered library for
 * controlling Parrot's connected toy: Jumping Sumo
 *
 * Copyright (C) 2014 I. Loreen
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <sstream>
#include <sys/time.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <cstring>
#include <cmath>

#include "common.h"

using namespace std;

void _handle_error (enum severity s, const char *func, const char *filename, const unsigned int line, const char *fmt ...)
{
	va_list ap;

	cout << endl;

	switch (s){
	case SEV_INFO : fprintf(stderr, "INFO("); break;
	case SEV_WARNING : fprintf(stderr, "WARNING("); break;
	default:
	case SEV_ERROR : fprintf(stderr, "ERROR("); break;
	};
	fprintf(stderr, "%s,%s:%i): ", func, filename, line);

	va_start(ap,fmt);
	vfprintf(stderr, fmt, ap);
	fflush(stderr);
	fprintf(stderr, "\n");
	fflush(stderr);
	va_end(ap);

	if (s==SEV_ERROR){
		exit(EXIT_FAILURE);
	}else{
		return;
	}
}

static struct timeval start_cap_time;
static uint32_t id;
static char timestamp[100];

static const char * strTime()
{
	double off;
	struct timeval t;
	gettimeofday(&t, NULL);

	off = t.tv_sec  + t.tv_usec/1000000.0;
	off -= start_cap_time.tv_sec + start_cap_time.tv_usec/1000000.0;

	snprintf(timestamp, 100, "%6d: %9.3f ", id, off);
	return timestamp;
}

static void printTime()
{
	dump(strTime());
}

void dumpPayload(const uint8_t *packet, uint32_t l, bool floats)
{
	uint32_t i;

	if (l < 3)
		return;

	printTime();
	dump("ascii: ");
	for (i = 0; i < l; i++)
		dump("%c", isprint(packet[i]) ? packet[i] : '.');
	dump("\n");

	printTime();
	dump("offs:  ");
	for (i = 0; i < l-3; i+=4)
		dump("%-11u     ", i);
	dump("\n");

	printTime();
	dump("hex  : ");
	for (i = 0; i < l; i++)
		dump("%02x  ", packet[i]);
	dump("\n");

	printTime();
	dump("ascii: ");
	for (i = 0; i < l; i++)
		dump("%c   ", isprint(packet[i]) ? packet[i] : '.');
	dump("\n");

	printTime();
	dump("8b:    ");
	for (i = 0; l && i < l; i++)
		dump("%-3u ", packet[i]);
	dump("\n");

	printTime();
	dump("16b 0: ");
	for (i = 0; l && i < l-1; i += 2)
		dump("%-5u   ", *((uint16_t *) &packet[i]) );
	dump("\n");

	printTime();
	dump("16b 1:     ");
	for (i = 1; l && i < l-1; i += 2)
		dump("%-5u   ", *((uint16_t *) &packet[i]) );
	dump("\n");

	printTime();
	dump("32b 0: ");
	for (i = 0; l && i < l-3; i += 4)
		dump("%-11u     ", *((uint32_t *) &packet[i]) );
	dump("\n");

	printTime();
	dump("32b 1:     ");
	for (i = 1; l && i < l-3; i += 4)
		dump("%-11u     ", *((uint32_t *) &packet[i]) );
	dump("\n");

	printTime();
	dump("32b 2:         ");
	for (i = 2; l && i < l-3; i += 4)
		dump("%-11u     ", *((uint32_t *) &packet[i]) );
	dump("\n");

	printTime();
	dump("32b 3:             ");
	for (i = 3; l && i < l-3; i += 4)
		dump("%-11u     ", *((uint32_t *) &packet[i]) );
	dump("\n");

	if (floats) {
		printTime();
		dump("32f 0: ");
		for (i = 0; l && i < l-3; i += 4)
			dump("%-11g     ", *((float *) &packet[i]) );
		dump("\n");

		printTime();
		dump("32f 1:     ");
		for (i = 1; l && i < l-3; i += 4)
			dump("%-11g     ", *((float *) &packet[i]) );
		dump("\n");

		printTime();
		dump("32f 2:         ");
		for (i = 2; l && i < l-3; i += 4)
			dump("%-11g     ", *((float *) &packet[i]) );
		dump("\n");

		printTime();
		dump("32f 3:             ");
		for (i = 3; l && i < l-3; i += 4)
			dump("%-11g     ", *((float *) &packet[i]) );
		dump("\n");

		if (l >= 8) {
			printTime();
			dump("64f 0: ");
			for (i = 0; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64f 1:     ");
			for (i = 1; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 2:         ");
			for (i = 2; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 3:             ");
			for (i = 3; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 4:                 ");
			for (i = 4; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 5:                     ");
			for (i = 5; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 6:                         ");
			for (i = 6; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 7:                             ");
			for (i = 7; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");
		}
	}
}
<commit_msg>warning: fix warning seen with clang-3.4<commit_after>/*
 * This file is part of the libsumo - a reverse-engineered library for
 * controlling Parrot's connected toy: Jumping Sumo
 *
 * Copyright (C) 2014 I. Loreen
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <sstream>
#include <sys/time.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <cstring>
#include <cmath>

#include "common.h"

using namespace std;

void _handle_error (enum severity s, const char *func, const char *filename, const unsigned int line, const char *fmt ...)
{
	va_list ap;

	cout << endl;

	switch (s){
	case SEV_INFO : fprintf(stderr, "INFO("); break;
	case SEV_WARNING : fprintf(stderr, "WARNING("); break;
	default:
	case SEV_ERROR : fprintf(stderr, "ERROR("); break;
	};
	fprintf(stderr, "%s,%s:%i): ", func, filename, line);

	va_start(ap,fmt);
	vfprintf(stderr, fmt, ap);
	fflush(stderr);
	fprintf(stderr, "\n");
	fflush(stderr);
	va_end(ap);

	if (s==SEV_ERROR){
		exit(EXIT_FAILURE);
	}else{
		return;
	}
}

static struct timeval start_cap_time;
static uint32_t id;
static char timestamp[100];

static const char * strTime()
{
	double off;
	struct timeval t;
	gettimeofday(&t, NULL);

	off = t.tv_sec  + t.tv_usec/1000000.0;
	off -= start_cap_time.tv_sec + start_cap_time.tv_usec/1000000.0;

	snprintf(timestamp, 100, "%6d: %9.3f ", id, off);
	return timestamp;
}

static void printTime()
{
	dump("%s", strTime());
}

void dumpPayload(const uint8_t *packet, uint32_t l, bool floats)
{
	uint32_t i;

	if (l < 3)
		return;

	printTime();
	dump("ascii: ");
	for (i = 0; i < l; i++)
		dump("%c", isprint(packet[i]) ? packet[i] : '.');
	dump("\n");

	printTime();
	dump("offs:  ");
	for (i = 0; i < l-3; i+=4)
		dump("%-11u     ", i);
	dump("\n");

	printTime();
	dump("hex  : ");
	for (i = 0; i < l; i++)
		dump("%02x  ", packet[i]);
	dump("\n");

	printTime();
	dump("ascii: ");
	for (i = 0; i < l; i++)
		dump("%c   ", isprint(packet[i]) ? packet[i] : '.');
	dump("\n");

	printTime();
	dump("8b:    ");
	for (i = 0; l && i < l; i++)
		dump("%-3u ", packet[i]);
	dump("\n");

	printTime();
	dump("16b 0: ");
	for (i = 0; l && i < l-1; i += 2)
		dump("%-5u   ", *((uint16_t *) &packet[i]) );
	dump("\n");

	printTime();
	dump("16b 1:     ");
	for (i = 1; l && i < l-1; i += 2)
		dump("%-5u   ", *((uint16_t *) &packet[i]) );
	dump("\n");

	printTime();
	dump("32b 0: ");
	for (i = 0; l && i < l-3; i += 4)
		dump("%-11u     ", *((uint32_t *) &packet[i]) );
	dump("\n");

	printTime();
	dump("32b 1:     ");
	for (i = 1; l && i < l-3; i += 4)
		dump("%-11u     ", *((uint32_t *) &packet[i]) );
	dump("\n");

	printTime();
	dump("32b 2:         ");
	for (i = 2; l && i < l-3; i += 4)
		dump("%-11u     ", *((uint32_t *) &packet[i]) );
	dump("\n");

	printTime();
	dump("32b 3:             ");
	for (i = 3; l && i < l-3; i += 4)
		dump("%-11u     ", *((uint32_t *) &packet[i]) );
	dump("\n");

	if (floats) {
		printTime();
		dump("32f 0: ");
		for (i = 0; l && i < l-3; i += 4)
			dump("%-11g     ", *((float *) &packet[i]) );
		dump("\n");

		printTime();
		dump("32f 1:     ");
		for (i = 1; l && i < l-3; i += 4)
			dump("%-11g     ", *((float *) &packet[i]) );
		dump("\n");

		printTime();
		dump("32f 2:         ");
		for (i = 2; l && i < l-3; i += 4)
			dump("%-11g     ", *((float *) &packet[i]) );
		dump("\n");

		printTime();
		dump("32f 3:             ");
		for (i = 3; l && i < l-3; i += 4)
			dump("%-11g     ", *((float *) &packet[i]) );
		dump("\n");

		if (l >= 8) {
			printTime();
			dump("64f 0: ");
			for (i = 0; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64f 1:     ");
			for (i = 1; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 2:         ");
			for (i = 2; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 3:             ");
			for (i = 3; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 4:                 ");
			for (i = 4; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 5:                     ");
			for (i = 5; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 6:                         ");
			for (i = 6; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");

			printTime();
			dump("64g 7:                             ");
			for (i = 7; l && i < l-7; i += 8)
				dump("%-27.4g     ", *((double *) &packet[i]) );
			dump("\n");
		}
	}
}
<|endoftext|>


<commit_before>#include "DistributeDriver.h"
#include "MasterManagerBase.h"
#include "DistributeRequestHooker.h"
#include "RequestLog.h"
#include "DistributeTest.hpp"

#include <util/scheduler.h>
#include <util/driver/Reader.h>
#include <util/driver/Writer.h>
#include <util/driver/writers/JsonWriter.h>
#include <util/driver/readers/JsonReader.h>
#include <util/driver/Keys.h>
#include <boost/bind.hpp>
#include <glog/logging.h>

using namespace izenelib::driver;

namespace sf1r
{

DistributeDriver::DistributeDriver()
{
    async_task_worker_ = boost::thread(&DistributeDriver::run, this);
    // only one write task can exist in distribute system.
    asyncWriteTasks_.resize(1);
}

void DistributeDriver::stop()
{
    async_task_worker_.interrupt();
    async_task_worker_.join();
    asyncWriteTasks_.clear();
}

void DistributeDriver::run()
{
    try
    {
        while(true)
        {
            boost::function<bool()> task;
            asyncWriteTasks_.pop(task);
            task();
            boost::this_thread::interruption_point();
        }
    }
    catch (boost::thread_interrupted&)
    {
        return;
    }
}

void DistributeDriver::init(const RouterPtr& router)
{
    router_ = router;
    MasterManagerBase::get()->setCallback(boost::bind(&DistributeDriver::on_new_req_available, this));
}

static bool callCronJob(Request::kCallType calltype, const std::string& jobname, const std::string& packed_data)
{
    DistributeRequestHooker::get()->processLocalBegin();
    DistributeTestSuit::incWriteRequestTimes("cron_" + jobname);
    bool ret = izenelib::util::Scheduler::runJobImmediatly(jobname, calltype, calltype == Request::FromLog);
    if (!ret)
    {
        LOG(ERROR) << "start cron job failed." << jobname;
    }
    else
    {
        LOG(INFO) << "cron job finished local: " << jobname;
    }
    DistributeRequestHooker::get()->processLocalFinished(ret);
    return ret;
}

static bool callHandler(izenelib::driver::Router::handler_ptr handler,
    Request::kCallType calltype, const std::string& packed_data,
    Request& request)
{
    try
    {
        DistributeRequestHooker::get()->processLocalBegin();
        Response response;
        response.setSuccess(true);
        static Poller tmp_poller;
        // prepare request
        handler->invoke(request,
            response,
            tmp_poller);

        LOG(INFO) << "write request send in DistributeDriver success.";
        return true;
    }
    catch(const std::exception& e)
    {
        LOG(ERROR) << "call request handler exception: " << e.what();
        DistributeRequestHooker::get()->processLocalFinished(false);
        throw;
    }
    return false;
}

static bool callCBWriteHandler(Request::kCallType calltype, const std::string& callback_name,
    const DistributeDriver::CBWriteHandlerT& cb_handler)
{
    DistributeRequestHooker::get()->processLocalBegin();
    DistributeTestSuit::incWriteRequestTimes("callback_" + callback_name);
    bool ret = cb_handler(calltype);
    if (!ret)
    {
        LOG(ERROR) << "callback handler failed." << callback_name;
    }
    else
    {
        LOG(INFO) << "a callback write request finished :" << callback_name;
    }
    DistributeRequestHooker::get()->processLocalFinished(ret);
    return ret;
}

void DistributeDriver::removeCallbackWriteHandler(const std::string& name)
{
    // no lock needed because of this will only happen while stopping collection,
    // it will be sure there is no any callback write request.
    callback_handlers_.erase(name);
    LOG(INFO) << "callback handler removed :" << name;
}

bool DistributeDriver::addCallbackWriteHandler(const std::string& name, const CBWriteHandlerT& handler)
{
    if (callback_handlers_.find(name) != callback_handlers_.end())
    {
        LOG(WARNING) << "callback handler already existed";
        return false;
    }
    if (!handler)
    {
        LOG(WARNING) << "callback NULL handler!";
        return false;
    }
    callback_handlers_[name] = handler;
    return true;
}

bool DistributeDriver::handleRequest(const std::string& reqjsondata, const std::string& packed_data, Request::kCallType calltype)
{
    static izenelib::driver::JsonReader reader;
    Value requestValue;
    if(reader.read(reqjsondata, requestValue))
    {
        if (requestValue.type() != Value::kObjectType)
        {
            LOG(ERROR) << "read request data type error: Malformed request: require an object as input.";
            return false;
        }
        Request request;
        request.assignTmp(requestValue);
        izenelib::driver::Router::handler_ptr handler = router_->find(
            request.controller(),
            request.action()
            );
        if (!handler)
        {
            LOG(ERROR) << "Handler not found for the request : " << request.controller() <<
                "," << request.action();
            return false;
        }
        if (!ReqLogMgr::isWriteRequest(request.controller(), request.action()))
        {
            LOG(ERROR) << "=== Wrong, not a write request in DistributeDriver!!";
            return false;
        }
        try
        {
            if (!asyncWriteTasks_.empty())
            {
                LOG(ERROR) << "another write task is running in async_task_worker_!!";
                return false;
            }

            DistributeTestSuit::incWriteRequestTimes(request.controller() + "_" + request.action());

            DistributeRequestHooker::get()->setHook(calltype, packed_data);
            request.setCallType(calltype);
            DistributeRequestHooker::get()->hookCurrentReq(packed_data);

            if (calltype == Request::FromLog)
            {
                // redo log must process the request one by one, so sync needed.
                return callHandler(handler, calltype, packed_data, request);
            }
            else
            {
                if (!async_task_worker_.interruption_requested())
                {
                    asyncWriteTasks_.push(boost::bind(&callHandler,
                            handler, calltype, packed_data, request));
                }
            }
            return true;
        }
        catch (const std::exception& e)
        {
            LOG(ERROR) << "process request exception: " << e.what();
        }
    }
    else
    {
        // malformed request
        LOG(WARNING) << "read request data error: " << reader.errorMessages();
    }
    return false;
}

bool DistributeDriver::handleReqFromLog(int reqtype, const std::string& reqjsondata, const std::string& packed_data)
{
    if ((ReqLogType)reqtype == Req_CronJob)
    {
        if (!asyncWriteTasks_.empty())
        {
            LOG(ERROR) << "another write task is running in async_task_worker_!!";
            return false;
        }

	    LOG(INFO) << "got a cron job request in log." << reqjsondata;
	    DistributeRequestHooker::get()->setHook(Request::FromLog, packed_data);
        DistributeRequestHooker::get()->hookCurrentReq(packed_data);

	    return callCronJob(Request::FromLog, reqjsondata, packed_data);
    }
    else if ((ReqLogType)reqtype == Req_Callback)
    {
        if (!asyncWriteTasks_.empty())
        {
            LOG(ERROR) << "another write task is running in async_task_worker_!!";
            return false;
        }

	    LOG(INFO) << "got a callback request in log." << reqjsondata;
        std::map<std::string, CBWriteHandlerT>::const_iterator it = callback_handlers_.find(reqjsondata);
        if (it == callback_handlers_.end())
        {
            LOG(WARNING) << "callback write request not found on the node: " << reqjsondata;
            return false;
        }

	    DistributeRequestHooker::get()->setHook(Request::FromLog, packed_data);
        DistributeRequestHooker::get()->hookCurrentReq(packed_data);
	    return callCBWriteHandler(Request::FromLog, reqjsondata, it->second);
    }

    return handleRequest(reqjsondata, packed_data, Request::FromLog);
}

bool DistributeDriver::handleReqFromPrimary(int reqtype, const std::string& reqjsondata, const std::string& packed_data)
{
    if ((ReqLogType)reqtype == Req_CronJob)
    {
        LOG(INFO) << "got a cron job request from primary." << reqjsondata;
        DistributeRequestHooker::get()->setHook(Request::FromPrimaryWorker, packed_data);
        DistributeRequestHooker::get()->hookCurrentReq(packed_data);

        if (!async_task_worker_.interruption_requested())
        {
            asyncWriteTasks_.push(boost::bind(&callCronJob,
                    Request::FromPrimaryWorker, reqjsondata, packed_data));
        }
        return true;
    }
    else if((ReqLogType)reqtype == Req_Callback)
    {
	    LOG(INFO) << "got a callback request from primary." << reqjsondata;

        std::map<std::string, CBWriteHandlerT>::const_iterator it = callback_handlers_.find(reqjsondata);
        if (it == callback_handlers_.end())
        {
            LOG(WARNING) << "callback write request not found on the node: " << reqjsondata;
            return false;
        }

	    DistributeRequestHooker::get()->setHook(Request::FromPrimaryWorker, packed_data);
        DistributeRequestHooker::get()->hookCurrentReq(packed_data);
        if (!async_task_worker_.interruption_requested())
        {
            asyncWriteTasks_.push(boost::bind(&callCBWriteHandler,
                    Request::FromPrimaryWorker, reqjsondata, it->second));
        }
        return true;
    }

    return handleRequest(reqjsondata, packed_data, Request::FromPrimaryWorker);
}

bool DistributeDriver::pushCallbackWrite(const std::string& name, const std::string& packed_data)
{
    LOG(INFO) << "a callback write pushed to queue: " << name;
    MasterManagerBase::get()->pushWriteReq(name + "::" + packed_data, "callback");
    return true;
}

bool DistributeDriver::on_new_req_available()
{
    if (!MasterManagerBase::get()->prepareWriteReq())
    {
        LOG(WARNING) << "prepare new request failed. maybe some other primary master prepared first. ";
        return false;
    }
    while(true)
    {
        std::string reqdata;
        std::string reqtype;
        if(!MasterManagerBase::get()->popWriteReq(reqdata, reqtype))
        {
            LOG(INFO) << "no more request.";
            return false;
        }

        if(reqtype.empty() && !handleRequest(reqdata, reqdata, Request::FromDistribute) )
        {
            LOG(WARNING) << "one write request failed to deliver :" << reqdata;
            // a write request failed to deliver means the worker did not
            // started to handle this request, so the request is ignored, and
            // continue to deliver next write request in the queue.
        }
        else if (reqtype == "api_from_shard")
        {
            if(!handleRequest(reqdata, reqdata, Request::FromOtherShard))
            {
                LOG(WARNING) << "one api write request from shard failed to deliver :" << reqdata;
            }
            else
            {
                break;
            }
        }
        else if (reqtype == "cron")
        {
            LOG(INFO) << "got a cron job request from queue." << reqdata;
            DistributeRequestHooker::get()->setHook(Request::FromDistribute, reqdata);
            DistributeRequestHooker::get()->hookCurrentReq(reqdata);

            if (!async_task_worker_.interruption_requested())
            {
                asyncWriteTasks_.push(boost::bind(&callCronJob,
                        Request::FromDistribute, reqdata, reqdata));
            }
            break;
        }
        else if (reqtype == "callback")
        {
            LOG(INFO) << "got a callback write request : " << reqdata;
            // get the callback name and packed_data.
            size_t split_pos = reqdata.find("::");
            if (split_pos == std::string::npos)
            {
                LOG(WARNING) << "callback data invalid.";
                continue;
            }
            std::string callback_name = reqdata.substr(0, split_pos);
            std::string packed_data = reqdata.substr(split_pos + 2);
            std::map<std::string, CBWriteHandlerT>::const_iterator it = callback_handlers_.find(callback_name);
            if (it == callback_handlers_.end())
            {
                LOG(WARNING) << "callback write request not found on the node: " << callback_name;
                continue;
            }
            DistributeRequestHooker::get()->setHook(Request::FromOtherShard, packed_data);
            DistributeRequestHooker::get()->hookCurrentReq(packed_data);

            if (!async_task_worker_.interruption_requested())
            {
                asyncWriteTasks_.push(boost::bind(&callCBWriteHandler, Request::FromOtherShard,
                        callback_name, it->second));
            }
            break;
        }
        else
        {
            // a write request deliver success from master to worker.
            // this mean the worker has started to process this request,
            // may be not finish writing, so we break here to wait the finished
            // event from primary worker.
            break;
        }
    }
    return true;
}

}
<commit_msg>handle stop while write request running<commit_after>#include "DistributeDriver.h"
#include "MasterManagerBase.h"
#include "DistributeRequestHooker.h"
#include "RequestLog.h"
#include "DistributeTest.hpp"

#include <util/scheduler.h>
#include <util/driver/Reader.h>
#include <util/driver/Writer.h>
#include <util/driver/writers/JsonWriter.h>
#include <util/driver/readers/JsonReader.h>
#include <util/driver/Keys.h>
#include <boost/bind.hpp>
#include <glog/logging.h>

using namespace izenelib::driver;

namespace sf1r
{

DistributeDriver::DistributeDriver()
{
    async_task_worker_ = boost::thread(&DistributeDriver::run, this);
    // only one write task can exist in distribute system.
    asyncWriteTasks_.resize(1);
}

void DistributeDriver::stop()
{
    async_task_worker_.interrupt();
    async_task_worker_.join();
    asyncWriteTasks_.clear();
}

void DistributeDriver::run()
{
    try
    {
        while(true)
        {
            boost::function<bool()> task;
            asyncWriteTasks_.pop(task);
            task();
            boost::this_thread::interruption_point();
        }
    }
    catch (boost::thread_interrupted&)
    {
        // if any request, run it.
        if (!asyncWriteTasks_.empty())
        {
            LOG(INFO) << "running last request before stopping.";
            boost::function<bool()> task;
            asyncWriteTasks_.pop(task);
            task();
        }
        return;
    }
    LOG(ERROR) << "run write thread error.";
    throw -1;
}

void DistributeDriver::init(const RouterPtr& router)
{
    router_ = router;
    MasterManagerBase::get()->setCallback(boost::bind(&DistributeDriver::on_new_req_available, this));
}

static bool callCronJob(Request::kCallType calltype, const std::string& jobname, const std::string& packed_data)
{
    DistributeRequestHooker::get()->processLocalBegin();
    DistributeTestSuit::incWriteRequestTimes("cron_" + jobname);
    bool ret = izenelib::util::Scheduler::runJobImmediatly(jobname, calltype, calltype == Request::FromLog);
    if (!ret)
    {
        LOG(ERROR) << "start cron job failed." << jobname;
    }
    else
    {
        LOG(INFO) << "cron job finished local: " << jobname;
    }
    DistributeRequestHooker::get()->processLocalFinished(ret);
    return ret;
}

static bool callHandler(izenelib::driver::Router::handler_ptr handler,
    Request::kCallType calltype, const std::string& packed_data,
    Request& request)
{
    try
    {
        DistributeRequestHooker::get()->processLocalBegin();
        Response response;
        response.setSuccess(true);
        static Poller tmp_poller;
        // prepare request
        handler->invoke(request,
            response,
            tmp_poller);

        LOG(INFO) << "write request send in DistributeDriver success.";
        return true;
    }
    catch(const std::exception& e)
    {
        LOG(ERROR) << "call request handler exception: " << e.what();
        DistributeRequestHooker::get()->processLocalFinished(false);
        throw;
    }
    return false;
}

static bool callCBWriteHandler(Request::kCallType calltype, const std::string& callback_name,
    const DistributeDriver::CBWriteHandlerT& cb_handler)
{
    DistributeRequestHooker::get()->processLocalBegin();
    DistributeTestSuit::incWriteRequestTimes("callback_" + callback_name);
    bool ret = cb_handler(calltype);
    if (!ret)
    {
        LOG(ERROR) << "callback handler failed." << callback_name;
    }
    else
    {
        LOG(INFO) << "a callback write request finished :" << callback_name;
    }
    DistributeRequestHooker::get()->processLocalFinished(ret);
    return ret;
}

void DistributeDriver::removeCallbackWriteHandler(const std::string& name)
{
    // no lock needed because of this will only happen while stopping collection,
    // it will be sure there is no any callback write request.
    callback_handlers_.erase(name);
    LOG(INFO) << "callback handler removed :" << name;
}

bool DistributeDriver::addCallbackWriteHandler(const std::string& name, const CBWriteHandlerT& handler)
{
    if (callback_handlers_.find(name) != callback_handlers_.end())
    {
        LOG(WARNING) << "callback handler already existed";
        return false;
    }
    if (!handler)
    {
        LOG(WARNING) << "callback NULL handler!";
        return false;
    }
    callback_handlers_[name] = handler;
    return true;
}

bool DistributeDriver::handleRequest(const std::string& reqjsondata, const std::string& packed_data, Request::kCallType calltype)
{
    static izenelib::driver::JsonReader reader;
    Value requestValue;
    if(reader.read(reqjsondata, requestValue))
    {
        if (requestValue.type() != Value::kObjectType)
        {
            LOG(ERROR) << "read request data type error: Malformed request: require an object as input.";
            return false;
        }
        Request request;
        request.assignTmp(requestValue);
        izenelib::driver::Router::handler_ptr handler = router_->find(
            request.controller(),
            request.action()
            );
        if (!handler)
        {
            LOG(ERROR) << "Handler not found for the request : " << request.controller() <<
                "," << request.action();
            return false;
        }
        if (!ReqLogMgr::isWriteRequest(request.controller(), request.action()))
        {
            LOG(ERROR) << "=== Wrong, not a write request in DistributeDriver!!";
            return false;
        }
        try
        {
            if (!asyncWriteTasks_.empty())
            {
                LOG(ERROR) << "another write task is running in async_task_worker_!!";
                return false;
            }

            DistributeTestSuit::incWriteRequestTimes(request.controller() + "_" + request.action());

            request.setCallType(calltype);

            if (calltype == Request::FromLog)
            {
                // redo log must process the request one by one, so sync needed.
                DistributeRequestHooker::get()->setHook(calltype, packed_data);
                DistributeRequestHooker::get()->hookCurrentReq(packed_data);
                return callHandler(handler, calltype, packed_data, request);
            }
            else
            {
                if (!async_task_worker_.interruption_requested())
                {
                    DistributeRequestHooker::get()->setHook(calltype, packed_data);
                    DistributeRequestHooker::get()->hookCurrentReq(packed_data);
                    asyncWriteTasks_.push(boost::bind(&callHandler,
                            handler, calltype, packed_data, request));
                }
                else
                {
                    LOG(INFO) << "write request has been interrupt.";
                    return false;
                }
            }
            return true;
        }
        catch (const std::exception& e)
        {
            LOG(ERROR) << "process request exception: " << e.what();
        }
    }
    else
    {
        // malformed request
        LOG(WARNING) << "read request data error: " << reader.errorMessages();
    }
    return false;
}

bool DistributeDriver::handleReqFromLog(int reqtype, const std::string& reqjsondata, const std::string& packed_data)
{
    if ((ReqLogType)reqtype == Req_CronJob)
    {
        if (!asyncWriteTasks_.empty())
        {
            LOG(ERROR) << "another write task is running in async_task_worker_!!";
            return false;
        }

	    LOG(INFO) << "got a cron job request in log." << reqjsondata;
	    DistributeRequestHooker::get()->setHook(Request::FromLog, packed_data);
        DistributeRequestHooker::get()->hookCurrentReq(packed_data);

	    return callCronJob(Request::FromLog, reqjsondata, packed_data);
    }
    else if ((ReqLogType)reqtype == Req_Callback)
    {
        if (!asyncWriteTasks_.empty())
        {
            LOG(ERROR) << "another write task is running in async_task_worker_!!";
            return false;
        }

	    LOG(INFO) << "got a callback request in log." << reqjsondata;
        std::map<std::string, CBWriteHandlerT>::const_iterator it = callback_handlers_.find(reqjsondata);
        if (it == callback_handlers_.end())
        {
            LOG(WARNING) << "callback write request not found on the node: " << reqjsondata;
            return false;
        }

	    DistributeRequestHooker::get()->setHook(Request::FromLog, packed_data);
        DistributeRequestHooker::get()->hookCurrentReq(packed_data);
	    return callCBWriteHandler(Request::FromLog, reqjsondata, it->second);
    }

    return handleRequest(reqjsondata, packed_data, Request::FromLog);
}

bool DistributeDriver::handleReqFromPrimary(int reqtype, const std::string& reqjsondata, const std::string& packed_data)
{
    if ((ReqLogType)reqtype == Req_CronJob)
    {
        LOG(INFO) << "got a cron job request from primary." << reqjsondata;

        if (!async_task_worker_.interruption_requested())
        {
            DistributeRequestHooker::get()->setHook(Request::FromPrimaryWorker, packed_data);
            DistributeRequestHooker::get()->hookCurrentReq(packed_data);
            asyncWriteTasks_.push(boost::bind(&callCronJob,
                    Request::FromPrimaryWorker, reqjsondata, packed_data));
        }
        else
        {
            LOG(INFO) << "write task has been interrupt : " << reqjsondata;
            return false;
        }
        return true;
    }
    else if((ReqLogType)reqtype == Req_Callback)
    {
	    LOG(INFO) << "got a callback request from primary." << reqjsondata;

        std::map<std::string, CBWriteHandlerT>::const_iterator it = callback_handlers_.find(reqjsondata);
        if (it == callback_handlers_.end())
        {
            LOG(WARNING) << "callback write request not found on the node: " << reqjsondata;
            return false;
        }

        if (!async_task_worker_.interruption_requested())
        {
            DistributeRequestHooker::get()->setHook(Request::FromPrimaryWorker, packed_data);
            DistributeRequestHooker::get()->hookCurrentReq(packed_data);
            asyncWriteTasks_.push(boost::bind(&callCBWriteHandler,
                    Request::FromPrimaryWorker, reqjsondata, it->second));
        }
        else
        {
            LOG(INFO) << "write task has been interrupt : " << reqjsondata;
            return false;
        }
        return true;
    }

    return handleRequest(reqjsondata, packed_data, Request::FromPrimaryWorker);
}

bool DistributeDriver::pushCallbackWrite(const std::string& name, const std::string& packed_data)
{
    LOG(INFO) << "a callback write pushed to queue: " << name;
    MasterManagerBase::get()->pushWriteReq(name + "::" + packed_data, "callback");
    return true;
}

bool DistributeDriver::on_new_req_available()
{
    if (!MasterManagerBase::get()->prepareWriteReq())
    {
        LOG(WARNING) << "prepare new request failed. maybe some other primary master prepared first. ";
        return false;
    }
    while(true)
    {
        std::string reqdata;
        std::string reqtype;
        if(!MasterManagerBase::get()->popWriteReq(reqdata, reqtype))
        {
            LOG(INFO) << "no more request.";
            return false;
        }

        if(reqtype.empty() && !handleRequest(reqdata, reqdata, Request::FromDistribute) )
        {
            LOG(WARNING) << "one write request failed to deliver :" << reqdata;
            // a write request failed to deliver means the worker did not
            // started to handle this request, so the request is ignored, and
            // continue to deliver next write request in the queue.
        }
        else if (reqtype == "api_from_shard")
        {
            if(!handleRequest(reqdata, reqdata, Request::FromOtherShard))
            {
                LOG(WARNING) << "one api write request from shard failed to deliver :" << reqdata;
            }
            else
            {
                break;
            }
        }
        else if (reqtype == "cron")
        {
            LOG(INFO) << "got a cron job request from queue." << reqdata;
            if (!async_task_worker_.interruption_requested())
            {
                DistributeRequestHooker::get()->setHook(Request::FromDistribute, reqdata);
                DistributeRequestHooker::get()->hookCurrentReq(reqdata);
                asyncWriteTasks_.push(boost::bind(&callCronJob,
                        Request::FromDistribute, reqdata, reqdata));
                break;
            }
            else
            {
                return false;
            }
        }
        else if (reqtype == "callback")
        {
            LOG(INFO) << "got a callback write request : " << reqdata;
            // get the callback name and packed_data.
            size_t split_pos = reqdata.find("::");
            if (split_pos == std::string::npos)
            {
                LOG(WARNING) << "callback data invalid.";
                continue;
            }
            std::string callback_name = reqdata.substr(0, split_pos);
            std::string packed_data = reqdata.substr(split_pos + 2);
            std::map<std::string, CBWriteHandlerT>::const_iterator it = callback_handlers_.find(callback_name);
            if (it == callback_handlers_.end())
            {
                LOG(WARNING) << "callback write request not found on the node: " << callback_name;
                continue;
            }
            if (!async_task_worker_.interruption_requested())
            {
                DistributeRequestHooker::get()->setHook(Request::FromOtherShard, packed_data);
                DistributeRequestHooker::get()->hookCurrentReq(packed_data);

                asyncWriteTasks_.push(boost::bind(&callCBWriteHandler, Request::FromOtherShard,
                        callback_name, it->second));
                break;
            }
            else
            {
                return false;
            }
        }
        else
        {
            // a write request deliver success from master to worker.
            // this mean the worker has started to process this request,
            // may be not finish writing, so we break here to wait the finished
            // event from primary worker.
            break;
        }
    }
    return true;
}

}
<|endoftext|>


<commit_before>
#include <cppexpose/reflection/Object.h>

#include <cassert>
#include <typeinfo>

#include <unordered_set>

#include <cppexpose/base/string_helpers.h>
#include <cppexpose/variant/Variant.h>

namespace
{
    static const char g_separator = '.';
    static const std::string g_separatorString = ".";
    static const std::string g_parent = "parent";
}

namespace cppexpose
{

Object::Object()
: Object("")
{
}

Object::Object(const std::string & name)
: m_className("Object")
{
    initProperty(name, nullptr, PropertyOwnership::None);
}

Object::~Object()
{
    clear();
}

const std::string & Object::className() const
{
    return m_className;
}

void Object::setClassName(const std::string & className)
{
    m_className = className;
}

void Object::clear()
{
    // Destroy managed properties
    while (m_managedProperties.size() > 0)
    {
        delete m_managedProperties.front();
    }
}

const std::unordered_map<std::string, AbstractProperty *> & Object::properties() const
{
    return m_propertiesMap;
}

bool Object::propertyExists(const std::string & name) const
{
    return m_propertiesMap.find(name) != m_propertiesMap.end();
}

AbstractProperty * Object::property(size_t index)
{
    if (index < m_properties.size()) {
        return m_properties[index];
    }

    return nullptr;
}

const AbstractProperty * Object::property(size_t index) const
{
    if (index < m_properties.size()) {
        return m_properties[index];
    }

    return nullptr;
}

AbstractProperty * Object::property(const std::string & path)
{
    std::vector<std::string> splittedPath = helper::split(path, g_separator);
    return const_cast<AbstractProperty *>(findProperty(splittedPath));
}

const AbstractProperty * Object::property(const std::string & path) const
{
    std::vector<std::string> splittedPath = helper::split(path, g_separator);
    return findProperty(splittedPath);
}

bool Object::addProperty(AbstractProperty * property, PropertyOwnership ownership)
{
    // Reject properties that have no name, or whose name already exists,
    // or that already have a parent object.
    if (!property || this->propertyExists(property->name()) || property->parent() != nullptr)
    {
        return false;
    }

    // Set parent
    property->setParent(this);

    // Invoke callback
    auto newIndex = m_properties.size();
    beforeAdd(newIndex, property);

    // Add property
    m_properties.push_back(property);
    m_propertiesMap.insert(std::make_pair(property->name(), property));

    // Take ownership over property?
    if (ownership == PropertyOwnership::Parent)
    {
        m_managedProperties.push_back(property);
    }

    // Invoke callback
    afterAdd(newIndex, property);

    // Success
    return true;
}

bool Object::removeProperty(AbstractProperty * property)
{
    // Reject properties that are not part of the object
    if (!property || property->parent() != this)
    {
        return false;
    }

    // Find property in object
    auto it = std::find(m_properties.begin(), m_properties.end(), property);
    if (it == m_properties.end())
    {
        return false;
    }

    // Get property index
    size_t index = std::distance(m_properties.begin(), it);

    // Invoke callback
    beforeRemove(index, property);

    // Remove property from object
    m_properties.erase(it);
    m_propertiesMap.erase(property->name());

    // Remove from managed list
    auto it2 = std::find(m_managedProperties.begin(), m_managedProperties.end(), property);
    if (it2 != m_managedProperties.end())
    {
        m_managedProperties.erase(it2);
    }

    // Reset property parent
    property->setParent(nullptr);

    // Invoke callback
    afterRemove(index, property);

    // Success
    return true;
}

bool Object::destroyProperty(AbstractProperty * property)
{
    // Check that property exists and belongs to the object
    if (!property || property->parent() != this)
    {
        return false;
    }

    // Chec that property is owned by the object
    auto it = std::find(m_managedProperties.begin(), m_managedProperties.end(), property);
    if (it == m_properties.end())
    {
        return false;
    }

    // Destroy property
    delete property;

    // Property removed
    return true;
}

const std::vector<Method> & Object::functions() const
{
    return m_functions;
}

bool Object::isObject() const
{
    return true;
}

AbstractTyped * Object::clone() const
{
    // [TODO]
    return new Object(name());
}

const std::type_info & Object::type() const
{
    return typeid(Object);
}

std::string Object::typeName() const
{
    return "Object";
}

bool Object::isReadOnly() const
{
    return false;
}

bool Object::isComposite() const
{
    return true;
}

size_t Object::numSubValues() const
{
    return m_properties.size();
}

AbstractTyped * Object::subValue(size_t index)
{
    if (index < m_properties.size()) {
        return m_properties[index];
    }

    return nullptr;
}

bool Object::isEnum() const
{
    return false;
}

bool Object::isArray() const
{
    return false;
}

bool Object::isVariant() const
{
    return false;
}

bool Object::isString() const
{
    return false;
}

bool Object::isBool() const
{
    return false;
}

bool Object::isNumber() const
{
    return false;
}

bool Object::isIntegral() const
{
    return false;
}

bool Object::isSignedIntegral() const
{
    return false;
}

bool Object::isUnsignedIntegral() const
{
    return false;
}

bool Object::isFloatingPoint() const
{
    return false;
}

Variant Object::toVariant() const
{
    // Create variant map from all properties in the object
    Variant map = Variant::map();
    for (auto it : m_propertiesMap) {
        // Get name and property
        std::string        name = it.first;
        AbstractProperty * prop = it.second;

        // Add to variant map
        (*map.asMap())[name] = prop->toVariant();
    }

    // Return variant representation
    return map;
}

bool Object::fromVariant(const Variant & value)
{
    // Check if variant is a map
    if (!value.isVariantMap()) {
        return false;
    }

    // Get all values from variant map
    for (auto it : *value.asMap()) {
        // Get name and value
        std::string     name = it.first;
        const Variant & var  = it.second;

        // If this names an existing property, set its value
        AbstractProperty * prop = this->property(name);
        if (prop) {
            prop->fromVariant(var);
        }
    }

    // Done
    return true;
}

std::string Object::toString() const
{
    // Convert object into JSON
    SerializerJSON json;
    return json.toString(this->toVariant());
}

bool Object::fromString(const std::string & str)
{
    // Convert from JSON
    Variant values;
    SerializerJSON json;
    if (json.fromString(values, str)) {
        return fromVariant(values);
    }

    // Error
    return false;
}

bool Object::toBool() const
{
    return false;
}

bool Object::fromBool(bool)
{
    return false;
}

long long Object::toLongLong() const
{
    return 0ll;
}

bool Object::fromLongLong(long long)
{
    return false;
}

unsigned long long Object::toULongLong() const
{
    return 0ull;
}

bool Object::fromULongLong(unsigned long long)
{
    return false;
}

double Object::toDouble() const
{
    return 0.0;
}

bool Object::fromDouble(double)
{
    return false;
}

std::string Object::relativePathTo(const Object * const other) const
{
    if(this == other){
        return g_separatorString;
    }

    // find all ancestors of "this"
    std::unordered_set<const Object*> ancestors;

    std::vector<std::string> thisPath;
    const Object * parent = nullptr;
    const Object * curObject = this;
    while(curObject->hasParent())
    {
        parent = curObject->parent();
        thisPath.push_back(curObject->name());
        ancestors.insert(parent);
        curObject = parent;
    }

    // find the intersection from "other"
    std::vector<std::string> otherPath;
    curObject = other;
    bool found = false;
    while(curObject->hasParent())
    {
        parent = curObject->parent();
        otherPath.push_back(curObject->name());
        if(ancestors.count(parent)){
            found = true;
        }
        curObject = parent;
    }

    // Ensure there was an intersection
    if(!found){
        return "";
    }

    // Shorten the paths
    while(thisPath.back() == otherPath.back()){
        thisPath.pop_back();
        otherPath.pop_back();
    }

    size_t numParents = thisPath.size();
    size_t numChildren = otherPath.size();

    // Build the relative Path
    std::fill(thisPath.begin(), thisPath.end(), g_parent);
    thisPath.insert(thisPath.end(), otherPath.begin(), otherPath.end());

    std::string pathString;
    // Reserve space for all elements, remembering the seperators and guessing the average length of a property name as 10
    pathString.reserve(numParents * (g_parent.size() + 1) + numChildren * (10 +1));

    for(const auto& element : thisPath){
        pathString.append(element);
        pathString.append(g_separatorString);
    }

    // The above writes one seperator to much
    pathString.pop_back();

    return pathString;
}

const AbstractProperty * Object::findProperty(const std::vector<std::string> & path) const
{
    // [TODO] Use iterative approach rather than recursion

    // Check if path is valid
    if (path.size() == 0) {
        return nullptr;
    }

    AbstractProperty * property = nullptr;

    // Check whether the path points to the parent
    if (path.front() == g_parent){

        // Check that the parent actually exists
        if(m_parent == nullptr){
            return nullptr;
        }

        property = m_parent;
    }
    else{

        // Check if first element of the path exists in this object
        if (!propertyExists(path.front())) {
            return nullptr;
        }

        // Get the respective property
        property = m_propertiesMap.at(path.front());
    }

    // If there are no more sub-paths, return the found property
    if (path.size() == 1) {
        return property;
    }

    // Otherwise, it is an element in the middle of the path, so ensure it is an object
    if (!property->isObject()) {
        return nullptr;
    }

    // Call recursively on sub-object
    return static_cast<Object *>(property)->findProperty({ path.begin() + 1, path.end() });
}

} // namespace cppexpose
<commit_msg>Correctly calculating the size of the intermediate string<commit_after>
#include <cppexpose/reflection/Object.h>

#include <cassert>
#include <typeinfo>

#include <unordered_set>

#include <cppexpose/base/string_helpers.h>
#include <cppexpose/variant/Variant.h>

namespace
{
    static const char g_separator = '.';
    static const std::string g_separatorString = ".";
    static const std::string g_parent = "parent";
}

namespace cppexpose
{

Object::Object()
: Object("")
{
}

Object::Object(const std::string & name)
: m_className("Object")
{
    initProperty(name, nullptr, PropertyOwnership::None);
}

Object::~Object()
{
    clear();
}

const std::string & Object::className() const
{
    return m_className;
}

void Object::setClassName(const std::string & className)
{
    m_className = className;
}

void Object::clear()
{
    // Destroy managed properties
    while (m_managedProperties.size() > 0)
    {
        delete m_managedProperties.front();
    }
}

const std::unordered_map<std::string, AbstractProperty *> & Object::properties() const
{
    return m_propertiesMap;
}

bool Object::propertyExists(const std::string & name) const
{
    return m_propertiesMap.find(name) != m_propertiesMap.end();
}

AbstractProperty * Object::property(size_t index)
{
    if (index < m_properties.size()) {
        return m_properties[index];
    }

    return nullptr;
}

const AbstractProperty * Object::property(size_t index) const
{
    if (index < m_properties.size()) {
        return m_properties[index];
    }

    return nullptr;
}

AbstractProperty * Object::property(const std::string & path)
{
    std::vector<std::string> splittedPath = helper::split(path, g_separator);
    return const_cast<AbstractProperty *>(findProperty(splittedPath));
}

const AbstractProperty * Object::property(const std::string & path) const
{
    std::vector<std::string> splittedPath = helper::split(path, g_separator);
    return findProperty(splittedPath);
}

bool Object::addProperty(AbstractProperty * property, PropertyOwnership ownership)
{
    // Reject properties that have no name, or whose name already exists,
    // or that already have a parent object.
    if (!property || this->propertyExists(property->name()) || property->parent() != nullptr)
    {
        return false;
    }

    // Set parent
    property->setParent(this);

    // Invoke callback
    auto newIndex = m_properties.size();
    beforeAdd(newIndex, property);

    // Add property
    m_properties.push_back(property);
    m_propertiesMap.insert(std::make_pair(property->name(), property));

    // Take ownership over property?
    if (ownership == PropertyOwnership::Parent)
    {
        m_managedProperties.push_back(property);
    }

    // Invoke callback
    afterAdd(newIndex, property);

    // Success
    return true;
}

bool Object::removeProperty(AbstractProperty * property)
{
    // Reject properties that are not part of the object
    if (!property || property->parent() != this)
    {
        return false;
    }

    // Find property in object
    auto it = std::find(m_properties.begin(), m_properties.end(), property);
    if (it == m_properties.end())
    {
        return false;
    }

    // Get property index
    size_t index = std::distance(m_properties.begin(), it);

    // Invoke callback
    beforeRemove(index, property);

    // Remove property from object
    m_properties.erase(it);
    m_propertiesMap.erase(property->name());

    // Remove from managed list
    auto it2 = std::find(m_managedProperties.begin(), m_managedProperties.end(), property);
    if (it2 != m_managedProperties.end())
    {
        m_managedProperties.erase(it2);
    }

    // Reset property parent
    property->setParent(nullptr);

    // Invoke callback
    afterRemove(index, property);

    // Success
    return true;
}

bool Object::destroyProperty(AbstractProperty * property)
{
    // Check that property exists and belongs to the object
    if (!property || property->parent() != this)
    {
        return false;
    }

    // Chec that property is owned by the object
    auto it = std::find(m_managedProperties.begin(), m_managedProperties.end(), property);
    if (it == m_properties.end())
    {
        return false;
    }

    // Destroy property
    delete property;

    // Property removed
    return true;
}

const std::vector<Method> & Object::functions() const
{
    return m_functions;
}

bool Object::isObject() const
{
    return true;
}

AbstractTyped * Object::clone() const
{
    // [TODO]
    return new Object(name());
}

const std::type_info & Object::type() const
{
    return typeid(Object);
}

std::string Object::typeName() const
{
    return "Object";
}

bool Object::isReadOnly() const
{
    return false;
}

bool Object::isComposite() const
{
    return true;
}

size_t Object::numSubValues() const
{
    return m_properties.size();
}

AbstractTyped * Object::subValue(size_t index)
{
    if (index < m_properties.size()) {
        return m_properties[index];
    }

    return nullptr;
}

bool Object::isEnum() const
{
    return false;
}

bool Object::isArray() const
{
    return false;
}

bool Object::isVariant() const
{
    return false;
}

bool Object::isString() const
{
    return false;
}

bool Object::isBool() const
{
    return false;
}

bool Object::isNumber() const
{
    return false;
}

bool Object::isIntegral() const
{
    return false;
}

bool Object::isSignedIntegral() const
{
    return false;
}

bool Object::isUnsignedIntegral() const
{
    return false;
}

bool Object::isFloatingPoint() const
{
    return false;
}

Variant Object::toVariant() const
{
    // Create variant map from all properties in the object
    Variant map = Variant::map();
    for (auto it : m_propertiesMap) {
        // Get name and property
        std::string        name = it.first;
        AbstractProperty * prop = it.second;

        // Add to variant map
        (*map.asMap())[name] = prop->toVariant();
    }

    // Return variant representation
    return map;
}

bool Object::fromVariant(const Variant & value)
{
    // Check if variant is a map
    if (!value.isVariantMap()) {
        return false;
    }

    // Get all values from variant map
    for (auto it : *value.asMap()) {
        // Get name and value
        std::string     name = it.first;
        const Variant & var  = it.second;

        // If this names an existing property, set its value
        AbstractProperty * prop = this->property(name);
        if (prop) {
            prop->fromVariant(var);
        }
    }

    // Done
    return true;
}

std::string Object::toString() const
{
    // Convert object into JSON
    SerializerJSON json;
    return json.toString(this->toVariant());
}

bool Object::fromString(const std::string & str)
{
    // Convert from JSON
    Variant values;
    SerializerJSON json;
    if (json.fromString(values, str)) {
        return fromVariant(values);
    }

    // Error
    return false;
}

bool Object::toBool() const
{
    return false;
}

bool Object::fromBool(bool)
{
    return false;
}

long long Object::toLongLong() const
{
    return 0ll;
}

bool Object::fromLongLong(long long)
{
    return false;
}

unsigned long long Object::toULongLong() const
{
    return 0ull;
}

bool Object::fromULongLong(unsigned long long)
{
    return false;
}

double Object::toDouble() const
{
    return 0.0;
}

bool Object::fromDouble(double)
{
    return false;
}

std::string Object::relativePathTo(const Object * const other) const
{
    if(this == other){
        return g_separatorString;
    }

    // find all ancestors of "this"
    std::unordered_set<const Object*> ancestors;

    std::vector<std::string> thisPath;
    const Object * parent = nullptr;
    const Object * curObject = this;
    while(curObject->hasParent())
    {
        parent = curObject->parent();
        thisPath.push_back(curObject->name());
        ancestors.insert(parent);
        curObject = parent;
    }

    // find the intersection from "other"
    std::vector<std::string> otherPath;
    curObject = other;
    bool found = false;
    while(curObject->hasParent())
    {
        parent = curObject->parent();
        otherPath.push_back(curObject->name());
        if(ancestors.count(parent)){
            found = true;
        }
        curObject = parent;
    }

    // Ensure there was an intersection
    if(!found){
        return "";
    }

    // Shorten the paths
    while(thisPath.back() == otherPath.back()){
        thisPath.pop_back();
        otherPath.pop_back();
    }

    size_t parentsCharCount = thisPath.size() * (g_parent.size() + 1);
    size_t childrenCharCount = 0;

    for(const auto & child : otherPath)
    {
        childrenCharCount += child.size() + 1;
    }

    // Build the relative Path
    std::fill(thisPath.begin(), thisPath.end(), g_parent);
    thisPath.insert(thisPath.end(), otherPath.begin(), otherPath.end());

    std::string pathString;
    pathString.reserve(parentsCharCount + childrenCharCount);

    for(const auto& element : thisPath){
        pathString.append(element);
        pathString.append(g_separatorString);
    }

    // The above writes one seperator to much
    pathString.pop_back();

    return pathString;
}

const AbstractProperty * Object::findProperty(const std::vector<std::string> & path) const
{
    // [TODO] Use iterative approach rather than recursion

    // Check if path is valid
    if (path.size() == 0) {
        return nullptr;
    }

    AbstractProperty * property = nullptr;

    // Check whether the path points to the parent
    if (path.front() == g_parent){

        // Check that the parent actually exists
        if(m_parent == nullptr){
            return nullptr;
        }

        property = m_parent;
    }
    else{

        // Check if first element of the path exists in this object
        if (!propertyExists(path.front())) {
            return nullptr;
        }

        // Get the respective property
        property = m_propertiesMap.at(path.front());
    }

    // If there are no more sub-paths, return the found property
    if (path.size() == 1) {
        return property;
    }

    // Otherwise, it is an element in the middle of the path, so ensure it is an object
    if (!property->isObject()) {
        return nullptr;
    }

    // Call recursively on sub-object
    return static_cast<Object *>(property)->findProperty({ path.begin() + 1, path.end() });
}

} // namespace cppexpose
<|endoftext|>