<commit_before>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

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

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "best_stoptime.h"

namespace navitia { namespace routing {

std::pair<const type::StopTime*, uint32_t>
best_stop_time(const type::JourneyPatternPoint* jpp,
               const DateTime dt,
               const type::VehicleProperties& vehicle_properties,
               const bool clockwise, bool disruption_active, const type::Data &data, bool reconstructing_path) {
    if(clockwise)
        return earliest_stop_time(jpp, dt, data, disruption_active, reconstructing_path, {}, vehicle_properties);
    else
        return tardiest_stop_time(jpp, dt, data, disruption_active, reconstructing_path, vehicle_properties);
}

/** Which is the first valid stop_time in this range ?
 *  Returns invalid_idx is none is
 */
const type::StopTime* next_valid_pick_up(type::idx_t idx, const type::idx_t end, const DateTime dt,
        const type::Data &data, bool reconstructing_path,
        const type::VehicleProperties &required_vehicle_properties,
        bool disruption_active){
    const auto date = DateTimeUtils::date(dt);
    const auto hour = DateTimeUtils::hour(dt);
    for(; idx < end; ++idx) {
        const type::StopTime* st = data.dataRaptor->st_idx_forward[idx];
        if (st->valid_end(reconstructing_path) && st->valid_hour(hour, true) &&
            ((disruption_active && st->arrival_adapted_validity_pattern->check(date)) || ((!disruption_active) && st->arrival_validity_pattern->check(date)))
            && st->vehicle_journey->accessible(required_vehicle_properties) ){
                return st;
        }
    }
    return nullptr;
}

/**
 * the valid_pick_up funciton can be called 2 differents ways:
 * - with a date time => we look for the new valid stop time valid the the day of the date time and after the hour of the date time.
 *      Note: if nothing found, we also look for a stop time the day after
 * - with a calendar and a hour => we look for the next valid stop time valid for the calendar and after the hour of the date time.
 */
std::pair<const type::StopTime*, DateTime>
valid_pick_up(const std::vector<uint32_t>::const_iterator begin, type::idx_t idx, const type::idx_t end, const DateTime dt,
        const type::Data &data, bool reconstructing_path,
        const type::VehicleProperties &vehicle_properties,
        bool disruption_active) {
    const type::StopTime* first_st = next_valid_pick_up(idx, end,
            dt, data, reconstructing_path, vehicle_properties, disruption_active);
    // If no trip was found, we look for one the day after
    if(first_st != nullptr) {
        return {first_st, dt};
    }
    idx = begin - data.dataRaptor->departure_times.begin();
    auto working_dt = DateTimeUtils::set(DateTimeUtils::date(dt)+1, 0);
    first_st = next_valid_pick_up(idx, end, working_dt,
        data, reconstructing_path, vehicle_properties,disruption_active);

    return {first_st, working_dt};
}

const type::StopTime* valid_pick_up(type::idx_t idx, const type::idx_t end, const uint32_t hour,
        const std::string calendar_id,
        const type::Data& data, bool reconstructing_path,
        const type::VehicleProperties& required_vehicle_properties) {
    for(; idx < end; ++idx) {
        const type::StopTime* st = data.dataRaptor->st_idx_forward[idx];
        if (! st->valid_end(reconstructing_path)) {
            continue; //we must be able to stop is this stop point
        }
        if (! st->valid_hour(hour, true)) {
            continue; //the stop must be after the given hour
        }
        if (st->vehicle_journey->associated_calendars.find(calendar_id) == st->vehicle_journey->associated_calendars.end()) {
            continue; //the calendar must be valid for this stop time
        }
        if (! st->vehicle_journey->accessible(required_vehicle_properties)) {
            continue; //the stop time must be accessible
        }
        return st;
    }
    return nullptr;
}

const type::StopTime* valid_drop_off(type::idx_t idx, const type::idx_t end, const DateTime dt,
               const type::Data &data, bool reconstructing_path,
               const type::VehicleProperties &required_vehicle_properties,
               bool disruption_active){
    const auto date = DateTimeUtils::date(dt);
    const auto hour = DateTimeUtils::hour(dt);
    for(; idx < end; ++idx) {
        const type::StopTime* st = data.dataRaptor->st_idx_backward[idx];
        if (st->valid_end(!reconstructing_path) && st->valid_hour(hour, false) &&
            ((disruption_active && st->arrival_adapted_validity_pattern->check(date)) || ((!disruption_active) && st->arrival_validity_pattern->check(date)))
            && st->vehicle_journey->accessible(required_vehicle_properties) ){
                return st;
        }
    }
    return nullptr;
}

std::pair<const type::StopTime*, uint32_t>
earliest_stop_time(const type::JourneyPatternPoint* jpp,
                   const DateTime dt, const type::Data &data,
                   bool disruption_active,
                   bool reconstructing_path,
                   boost::optional<const std::string> calendar_id,
                   const type::VehicleProperties& vehicle_properties) {
    //On cherche le plus petit stop time de la journey_pattern >= dt.hour()
    auto begin = data.dataRaptor->departure_times.begin() +
            data.dataRaptor->first_stop_time[jpp->journey_pattern->idx] +
            jpp->order * data.dataRaptor->nb_trips[jpp->journey_pattern->idx];
    auto end = begin + data.dataRaptor->nb_trips[jpp->journey_pattern->idx];
    auto it = std::lower_bound(begin, end, DateTimeUtils::hour(dt),
                               bound_predicate_earliest);

    type::idx_t idx = it - data.dataRaptor->departure_times.begin();
    type::idx_t end_idx = (begin - data.dataRaptor->departure_times.begin()) +
                           data.dataRaptor->nb_trips[jpp->journey_pattern->idx];

    //On renvoie le premier trip valide
    std::pair<const type::StopTime*, DateTime> first_st = {nullptr, 0};
    if (! calendar_id) {
        first_st = valid_pick_up(begin, idx, end_idx, dt, data, reconstructing_path, vehicle_properties, disruption_active);
    } else {
        first_st.first = valid_pick_up(idx, end_idx, DateTimeUtils::hour(dt), *calendar_id, data, reconstructing_path, vehicle_properties);
        first_st.second = dt;
    }

    if(first_st.first != nullptr) {
        if(!first_st.first->is_frequency()) {
            DateTimeUtils::update(first_st.second, first_st.first->departure_time);
        } else {
            first_st.second = dt;
            const DateTime tmp_dt = f_departure_time(DateTimeUtils::hour(first_st.second), first_st.first);
            DateTimeUtils::update(first_st.second, DateTimeUtils::hour(tmp_dt));
        }
        return first_st;
    }
    return {nullptr, 0};
}

std::pair<const type::StopTime*, uint32_t>
tardiest_stop_time(const type::JourneyPatternPoint* jpp,
                   const DateTime dt, const type::Data &data, bool disruption_active,
                   bool reconstructing_path,
                   const type::VehicleProperties& vehicle_properties) {
    //On cherche le plus grand stop time de la journey_pattern <= dt.hour()
    const auto begin = data.dataRaptor->arrival_times.begin() +
                       data.dataRaptor->first_stop_time[jpp->journey_pattern->idx] +
                       jpp->order * data.dataRaptor->nb_trips[jpp->journey_pattern->idx];
    const auto end = begin + data.dataRaptor->nb_trips[jpp->journey_pattern->idx];
    auto it = std::lower_bound(begin, end, DateTimeUtils::hour(dt), bound_predicate_tardiest);

    type::idx_t idx = it - data.dataRaptor->arrival_times.begin();
    type::idx_t end_idx = (begin - data.dataRaptor->arrival_times.begin()) +
                           data.dataRaptor->nb_trips[jpp->journey_pattern->idx];

    const type::StopTime* first_st = valid_drop_off(idx, end_idx,
            dt, data,
            reconstructing_path, vehicle_properties, disruption_active);

    auto working_dt = dt;
    // If no trip was found, we look for one the day before
    if(first_st == nullptr && DateTimeUtils::date(dt) > 0){
        idx = begin - data.dataRaptor->arrival_times.begin();
        working_dt = DateTimeUtils::set(DateTimeUtils::date(working_dt) - 1,
                                        DateTimeUtils::SECONDS_PER_DAY - 1);
        first_st = valid_drop_off(idx, end_idx, working_dt, data, reconstructing_path,
                vehicle_properties, disruption_active);
    }

    if(first_st != nullptr){
        if(!first_st->is_frequency()) {
            DateTimeUtils::update(working_dt, DateTimeUtils::hour(first_st->arrival_time), false);
        } else {
            working_dt = dt;
            const DateTime tmp_dt = f_arrival_time(DateTimeUtils::hour(working_dt), first_st);
            DateTimeUtils::update(working_dt, DateTimeUtils::hour(tmp_dt), false);
        }
        return std::make_pair(first_st, working_dt);
    }

    //Cette journey_pattern ne comporte aucun trip compatible
    return std::make_pair(nullptr, 0);
}
}}

<commit_msg>Use the departure validity pattern for pickup<commit_after>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

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

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "best_stoptime.h"

namespace navitia { namespace routing {

std::pair<const type::StopTime*, uint32_t>
best_stop_time(const type::JourneyPatternPoint* jpp,
               const DateTime dt,
               const type::VehicleProperties& vehicle_properties,
               const bool clockwise, bool disruption_active, const type::Data &data, bool reconstructing_path) {
    if(clockwise)
        return earliest_stop_time(jpp, dt, data, disruption_active, reconstructing_path, {}, vehicle_properties);
    else
        return tardiest_stop_time(jpp, dt, data, disruption_active, reconstructing_path, vehicle_properties);
}

/** Which is the first valid stop_time in this range ?
 *  Returns invalid_idx is none is
 */
const type::StopTime* next_valid_pick_up(type::idx_t idx, const type::idx_t end, const DateTime dt,
        const type::Data &data, bool reconstructing_path,
        const type::VehicleProperties &required_vehicle_properties,
        bool disruption_active){
    const auto date = DateTimeUtils::date(dt);
    const auto hour = DateTimeUtils::hour(dt);
    for(; idx < end; ++idx) {
        const type::StopTime* st = data.dataRaptor->st_idx_forward[idx];
        if (st->valid_end(reconstructing_path) && st->valid_hour(hour, true) &&
            ((disruption_active && st->departure_adapted_validity_pattern->check(date)) || ((!disruption_active) && st->departure_validity_pattern->check(date)))
            && st->vehicle_journey->accessible(required_vehicle_properties) ){
                return st;
        }
    }
    return nullptr;
}

/**
 * the valid_pick_up funciton can be called 2 differents ways:
 * - with a date time => we look for the new valid stop time valid the the day of the date time and after the hour of the date time.
 *      Note: if nothing found, we also look for a stop time the day after
 * - with a calendar and a hour => we look for the next valid stop time valid for the calendar and after the hour of the date time.
 */
std::pair<const type::StopTime*, DateTime>
valid_pick_up(const std::vector<uint32_t>::const_iterator begin, type::idx_t idx, const type::idx_t end, const DateTime dt,
        const type::Data &data, bool reconstructing_path,
        const type::VehicleProperties &vehicle_properties,
        bool disruption_active) {
    const type::StopTime* first_st = next_valid_pick_up(idx, end,
            dt, data, reconstructing_path, vehicle_properties, disruption_active);
    // If no trip was found, we look for one the day after
    if(first_st != nullptr) {
        return {first_st, dt};
    }
    idx = begin - data.dataRaptor->departure_times.begin();
    auto working_dt = DateTimeUtils::set(DateTimeUtils::date(dt)+1, 0);
    first_st = next_valid_pick_up(idx, end, working_dt,
        data, reconstructing_path, vehicle_properties,disruption_active);

    return {first_st, working_dt};
}

const type::StopTime* valid_pick_up(type::idx_t idx, const type::idx_t end, const uint32_t hour,
        const std::string calendar_id,
        const type::Data& data, bool reconstructing_path,
        const type::VehicleProperties& required_vehicle_properties) {
    for(; idx < end; ++idx) {
        const type::StopTime* st = data.dataRaptor->st_idx_forward[idx];
        if (! st->valid_end(reconstructing_path)) {
            continue; //we must be able to stop is this stop point
        }
        if (! st->valid_hour(hour, true)) {
            continue; //the stop must be after the given hour
        }
        if (st->vehicle_journey->associated_calendars.find(calendar_id) == st->vehicle_journey->associated_calendars.end()) {
            continue; //the calendar must be valid for this stop time
        }
        if (! st->vehicle_journey->accessible(required_vehicle_properties)) {
            continue; //the stop time must be accessible
        }
        return st;
    }
    return nullptr;
}

const type::StopTime* valid_drop_off(type::idx_t idx, const type::idx_t end, const DateTime dt,
               const type::Data &data, bool reconstructing_path,
               const type::VehicleProperties &required_vehicle_properties,
               bool disruption_active){
    const auto date = DateTimeUtils::date(dt);
    const auto hour = DateTimeUtils::hour(dt);
    for(; idx < end; ++idx) {
        const type::StopTime* st = data.dataRaptor->st_idx_backward[idx];
        if (st->valid_end(!reconstructing_path) && st->valid_hour(hour, false) &&
            ((disruption_active && st->arrival_adapted_validity_pattern->check(date)) || ((!disruption_active) && st->arrival_validity_pattern->check(date)))
            && st->vehicle_journey->accessible(required_vehicle_properties) ){
                return st;
        }
    }
    return nullptr;
}

std::pair<const type::StopTime*, uint32_t>
earliest_stop_time(const type::JourneyPatternPoint* jpp,
                   const DateTime dt, const type::Data &data,
                   bool disruption_active,
                   bool reconstructing_path,
                   boost::optional<const std::string> calendar_id,
                   const type::VehicleProperties& vehicle_properties) {
    //On cherche le plus petit stop time de la journey_pattern >= dt.hour()
    auto begin = data.dataRaptor->departure_times.begin() +
            data.dataRaptor->first_stop_time[jpp->journey_pattern->idx] +
            jpp->order * data.dataRaptor->nb_trips[jpp->journey_pattern->idx];
    auto end = begin + data.dataRaptor->nb_trips[jpp->journey_pattern->idx];
    auto it = std::lower_bound(begin, end, DateTimeUtils::hour(dt),
                               bound_predicate_earliest);

    type::idx_t idx = it - data.dataRaptor->departure_times.begin();
    type::idx_t end_idx = (begin - data.dataRaptor->departure_times.begin()) +
                           data.dataRaptor->nb_trips[jpp->journey_pattern->idx];

    //On renvoie le premier trip valide
    std::pair<const type::StopTime*, DateTime> first_st = {nullptr, 0};
    if (! calendar_id) {
        first_st = valid_pick_up(begin, idx, end_idx, dt, data, reconstructing_path, vehicle_properties, disruption_active);
    } else {
        first_st.first = valid_pick_up(idx, end_idx, DateTimeUtils::hour(dt), *calendar_id, data, reconstructing_path, vehicle_properties);
        first_st.second = dt;
    }

    if(first_st.first != nullptr) {
        if(!first_st.first->is_frequency()) {
            DateTimeUtils::update(first_st.second, first_st.first->departure_time);
        } else {
            first_st.second = dt;
            const DateTime tmp_dt = f_departure_time(DateTimeUtils::hour(first_st.second), first_st.first);
            DateTimeUtils::update(first_st.second, DateTimeUtils::hour(tmp_dt));
        }
        return first_st;
    }
    return {nullptr, 0};
}

std::pair<const type::StopTime*, uint32_t>
tardiest_stop_time(const type::JourneyPatternPoint* jpp,
                   const DateTime dt, const type::Data &data, bool disruption_active,
                   bool reconstructing_path,
                   const type::VehicleProperties& vehicle_properties) {
    //On cherche le plus grand stop time de la journey_pattern <= dt.hour()
    const auto begin = data.dataRaptor->arrival_times.begin() +
                       data.dataRaptor->first_stop_time[jpp->journey_pattern->idx] +
                       jpp->order * data.dataRaptor->nb_trips[jpp->journey_pattern->idx];
    const auto end = begin + data.dataRaptor->nb_trips[jpp->journey_pattern->idx];
    auto it = std::lower_bound(begin, end, DateTimeUtils::hour(dt), bound_predicate_tardiest);

    type::idx_t idx = it - data.dataRaptor->arrival_times.begin();
    type::idx_t end_idx = (begin - data.dataRaptor->arrival_times.begin()) +
                           data.dataRaptor->nb_trips[jpp->journey_pattern->idx];

    const type::StopTime* first_st = valid_drop_off(idx, end_idx,
            dt, data,
            reconstructing_path, vehicle_properties, disruption_active);

    auto working_dt = dt;
    // If no trip was found, we look for one the day before
    if(first_st == nullptr && DateTimeUtils::date(dt) > 0){
        idx = begin - data.dataRaptor->arrival_times.begin();
        working_dt = DateTimeUtils::set(DateTimeUtils::date(working_dt) - 1,
                                        DateTimeUtils::SECONDS_PER_DAY - 1);
        first_st = valid_drop_off(idx, end_idx, working_dt, data, reconstructing_path,
                vehicle_properties, disruption_active);
    }

    if(first_st != nullptr){
        if(!first_st->is_frequency()) {
            DateTimeUtils::update(working_dt, DateTimeUtils::hour(first_st->arrival_time), false);
        } else {
            working_dt = dt;
            const DateTime tmp_dt = f_arrival_time(DateTimeUtils::hour(working_dt), first_st);
            DateTimeUtils::update(working_dt, DateTimeUtils::hour(tmp_dt), false);
        }
        return std::make_pair(first_st, working_dt);
    }

    //Cette journey_pattern ne comporte aucun trip compatible
    return std::make_pair(nullptr, 0);
}
}}

<|endoftext|>


<commit_before>//============================================================================//
// File:          test:qcan_frame.cpp                                         //
// Description:   QCAN classes - Test QCan frame                              //
//                                                                            //
// Copyright (C) MicroControl GmbH & Co. KG                                   //
// 53844 Troisdorf - Germany                                                  //
// www.microcontrol.net                                                       //
//                                                                            //
//----------------------------------------------------------------------------//
// 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, the following disclaimer and           //
//    the referenced file 'LICENSE'.                                          //
// 2. Redistributions in binary form must reproduce the above copyright       //
//    notice, this list of conditions and the following disclaimer in the     //
//    documentation and/or other materials provided with the distribution.    //
// 3. Neither the name of MicroControl nor the names of its contributors      //
//    may be used to endorse or promote products derived from this software   //
//    without specific prior written permission.                              //
//                                                                            //
// Provided that this notice is retained in full, this software may be        //
// distributed under the terms of the GNU Lesser General Public License       //
// ("LGPL") version 3 as distributed in the 'LICENSE' file.                   //
//                                                                            //
//============================================================================//

#include "test_qcan_frame.hpp"

TestQCanFrame::TestQCanFrame()
{

}

TestQCanFrame::~TestQCanFrame()
{

}

//----------------------------------------------------------------------------//
// initTestCase()                                                             //
// prepare test cases                                                         //
//----------------------------------------------------------------------------//
void TestQCanFrame::initTestCase()
{
   pclCanStdP = new QCanFrame(QCanFrame::eTYPE_CAN_STD);
   pclCanExtP = new QCanFrame(QCanFrame::eTYPE_CAN_EXT);
   pclFdStdP  = new QCanFrame(QCanFrame::eTYPE_FD_STD);
   pclFdExtP  = new QCanFrame(QCanFrame::eTYPE_FD_EXT);

   pclFrameP  = new QCanFrame();
}

//----------------------------------------------------------------------------//
// checkFrameType()                                                           //
// check frame types                                                          //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkFrameType()
{
   QVERIFY(pclCanStdP->frameType() == QCanFrame::eTYPE_CAN_STD);
   QVERIFY(pclCanExtP->frameType() == QCanFrame::eTYPE_CAN_EXT);
   QVERIFY(pclFdStdP->frameType()  == QCanFrame::eTYPE_FD_STD);
   QVERIFY(pclFdExtP->frameType()  == QCanFrame::eTYPE_FD_EXT);
}

//----------------------------------------------------------------------------//
// checkFrameId()                                                             //
// check frame identifier                                                     //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkFrameId()
{
   uint32_t ulIdValueT;

   for(ulIdValueT = 0; ulIdValueT <= 0x0000FFFF; ulIdValueT++)
   {
      pclCanStdP->setStdId((uint16_t)ulIdValueT);
      pclCanExtP->setExtId(ulIdValueT);

      *pclFrameP = *pclCanStdP;
      if(ulIdValueT <= 0x07FF)
      {
         QVERIFY(pclCanStdP->identifier() == ulIdValueT);
         QVERIFY(pclFrameP->identifier()  == ulIdValueT);
      }
      else
      {
         QVERIFY(pclCanStdP->identifier() == (ulIdValueT & 0x07FF));
         QVERIFY(pclFrameP->identifier()  == (ulIdValueT & 0x07FF));
      }
      QVERIFY(pclCanExtP->identifier() == ulIdValueT);

      QVERIFY(pclCanStdP->isExtended() == 0);
      QVERIFY(pclFrameP->isExtended()  == 0);
   }
}

//----------------------------------------------------------------------------//
// checkFrameDlc()                                                            //
// check frame DLC                                                            //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkFrameDlc()
{
   uint8_t  ubSizeT;

   //----------------------------------------------------------------
   // Test 1: set the DLC value for classic CAN and CAN FD and
   // check the result for the dataSize() return
   //
   for(ubSizeT = 0; ubSizeT < 16; ubSizeT++)
   {
      pclCanStdP->setDlc(ubSizeT);
      pclFdStdP->setDlc(ubSizeT);

      //--------------------------------------------------------
      // check data size
      //
      if(ubSizeT < 9)
      {
         QVERIFY(pclCanStdP->dataSize() == ubSizeT);
         QVERIFY(pclFdStdP->dataSize() == ubSizeT);
      }
      else
      {
         //------------------------------------------------
         // copy FD frame contents and convert type to
         // classic CAN
         //
         *pclFrameP = *pclFdStdP;
         pclFrameP->setFrameType(QCanFrame::eTYPE_CAN_STD);

         //------------------------------------------------
         // make sure maximum dataSize of classic CAN is 8
         //
         QVERIFY(pclFrameP->dataSize()  == 8);
         QVERIFY(pclCanStdP->dataSize() == 8);

         //------------------------------------------------
         // check data size of CAN FD
         //
         switch(ubSizeT)
         {
            case 9:
               QVERIFY(pclFdStdP->dataSize() == 12);
               break;

            case 10:
               QVERIFY(pclFdStdP->dataSize() == 16);
               break;

            case 11:
               QVERIFY(pclFdStdP->dataSize() == 20);
               break;

            case 12:
               QVERIFY(pclFdStdP->dataSize() == 24);
               break;

            case 13:
               QVERIFY(pclFdStdP->dataSize() == 32);
               break;

            case 14:
               QVERIFY(pclFdStdP->dataSize() == 48);
               break;

            case 15:
               QVERIFY(pclFdStdP->dataSize() == 64);
               break;

            default:

               break;
         }
      }

      //--------------------------------------------------------
      // check DLC
      //
      if(ubSizeT < 9)
      {
         QVERIFY(pclCanStdP->dlc() == ubSizeT);
         QVERIFY(pclFdStdP->dlc() == ubSizeT);
      }
      else
      {
         QVERIFY(pclCanStdP->dlc() == 8);
         QVERIFY(pclFdStdP->dlc() == ubSizeT);
      }
   }

   //----------------------------------------------------------------
   // Test 2: set DLC value out of range
   //
   pclCanStdP->setDlc(22);
   pclFdStdP->setDlc(22);
   QVERIFY(pclCanStdP->dlc() <= 8);
   QVERIFY(pclFdStdP->dlc()  <= 15);

}

void TestQCanFrame::checkFrameDataSize()
{
   uint8_t  ubSizeT;

   //----------------------------------------------------------------
   // Test 3: set the data size value for classic CAN and CAN FD and
   // check the result for the dlc() return
   //
   for(ubSizeT = 0; ubSizeT < 70; ubSizeT++)
   {
      pclCanStdP->setDataSize(ubSizeT);
      pclFdStdP->setDataSize(ubSizeT);

   }
}

//----------------------------------------------------------------------------//
// checkFrameData()                                                           //
// check frame data                                                           //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkFrameData()
{
   pclCanStdP->setDlc(4);
   pclCanStdP->setData(0, 0x12);
   pclCanStdP->setData(1, 0x34);
   pclCanStdP->setData(2, 0x56);
   pclCanStdP->setData(3, 0x78);

   QVERIFY(pclCanStdP->dataUInt16(0, 1) == 0x1234);
   QVERIFY(pclCanStdP->dataUInt16(1, 1) == 0x3456);
   QVERIFY(pclCanStdP->dataUInt16(2, 1) == 0x5678);
   QVERIFY(pclCanStdP->dataUInt16(3, 1) == 0x0000);

   QVERIFY(pclCanStdP->dataUInt32(0, 1) == 0x12345678);

   pclCanStdP->setDataUInt16(0, 0xAABB);
   QVERIFY(pclCanStdP->data(0) == 0xBB);
   QVERIFY(pclCanStdP->data(1) == 0xAA);
   QVERIFY(pclCanStdP->dataUInt16(0, 0) == 0xAABB);

}

//----------------------------------------------------------------------------//
// checkFrameRemote()                                                         //
// check remote frame                                                         //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkFrameRemote()
{

}

//----------------------------------------------------------------------------//
// checkFrameData()                                                           //
// check frame data                                                           //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkByteArray()
{
   QByteArray  clByteArrayT;

   for(uint8_t ubCntT = 0; ubCntT < 9; ubCntT++)
   {
      pclCanStdP->setStdId(0x301 + ubCntT);
      pclCanStdP->setDlc(ubCntT);
      pclCanStdP->setData(0, ubCntT);
      pclCanStdP->setData(1, 0x10 + ubCntT);
      pclCanStdP->setData(2, 0x20 + ubCntT);
      pclCanStdP->setData(3, 0x30 + ubCntT);
      pclCanStdP->setData(4, 0x40 + ubCntT);
      pclCanStdP->setData(5, 0x50 + ubCntT);
      pclCanStdP->setData(6, 0x60 + ubCntT);
      pclCanStdP->setData(7, 0x70 + ubCntT);

      pclCanStdP->setMarker(0x223344);
      pclCanStdP->setUser(0xAB1023);

      clByteArrayT = pclCanStdP->toByteArray();

      QVERIFY(pclFrameP->fromByteArray(clByteArrayT) == true);

      QVERIFY(pclFrameP->identifier() == (0x301 + ubCntT));
      QVERIFY(pclFrameP->dlc()   == (ubCntT));
      if(ubCntT == 4)
      {
         QVERIFY(pclFrameP->data(0) == (ubCntT));
         QVERIFY(pclFrameP->data(1) == (0x10 + ubCntT));
         QVERIFY(pclFrameP->data(2) == (0x20 + ubCntT));
         QVERIFY(pclFrameP->data(3) == (0x30 + ubCntT));
         QVERIFY(pclFrameP->data(4) == 0);
      }

   }
}

//----------------------------------------------------------------------------//
// cleanupTestCase()                                                          //
// cleanup test cases                                                         //
//----------------------------------------------------------------------------//

void TestQCanFrame::cleanupTestCase()
{
   delete(pclCanStdP);
   delete(pclCanExtP);
   delete(pclFdStdP);
   delete(pclFdExtP);

   delete(pclFrameP);
}

<commit_msg>Replace setStdId() and setExtId() functions<commit_after>//============================================================================//
// File:          test:qcan_frame.cpp                                         //
// Description:   QCAN classes - Test QCan frame                              //
//                                                                            //
// Copyright (C) MicroControl GmbH & Co. KG                                   //
// 53844 Troisdorf - Germany                                                  //
// www.microcontrol.net                                                       //
//                                                                            //
//----------------------------------------------------------------------------//
// 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, the following disclaimer and           //
//    the referenced file 'LICENSE'.                                          //
// 2. Redistributions in binary form must reproduce the above copyright       //
//    notice, this list of conditions and the following disclaimer in the     //
//    documentation and/or other materials provided with the distribution.    //
// 3. Neither the name of MicroControl nor the names of its contributors      //
//    may be used to endorse or promote products derived from this software   //
//    without specific prior written permission.                              //
//                                                                            //
// Provided that this notice is retained in full, this software may be        //
// distributed under the terms of the GNU Lesser General Public License       //
// ("LGPL") version 3 as distributed in the 'LICENSE' file.                   //
//                                                                            //
//============================================================================//

#include "test_qcan_frame.hpp"

TestQCanFrame::TestQCanFrame()
{

}

TestQCanFrame::~TestQCanFrame()
{

}

//----------------------------------------------------------------------------//
// initTestCase()                                                             //
// prepare test cases                                                         //
//----------------------------------------------------------------------------//
void TestQCanFrame::initTestCase()
{
   pclCanStdP = new QCanFrame(QCanFrame::eTYPE_CAN_STD);
   pclCanExtP = new QCanFrame(QCanFrame::eTYPE_CAN_EXT);
   pclFdStdP  = new QCanFrame(QCanFrame::eTYPE_FD_STD);
   pclFdExtP  = new QCanFrame(QCanFrame::eTYPE_FD_EXT);

   pclFrameP  = new QCanFrame();
}

//----------------------------------------------------------------------------//
// checkFrameType()                                                           //
// check frame types                                                          //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkFrameType()
{
   QVERIFY(pclCanStdP->frameType() == QCanFrame::eTYPE_CAN_STD);
   QVERIFY(pclCanExtP->frameType() == QCanFrame::eTYPE_CAN_EXT);
   QVERIFY(pclFdStdP->frameType()  == QCanFrame::eTYPE_FD_STD);
   QVERIFY(pclFdExtP->frameType()  == QCanFrame::eTYPE_FD_EXT);
}

//----------------------------------------------------------------------------//
// checkFrameId()                                                             //
// check frame identifier                                                     //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkFrameId()
{
   uint32_t ulIdValueT;

   for(ulIdValueT = 0; ulIdValueT <= 0x0000FFFF; ulIdValueT++)
   {
      pclCanStdP->setIdentifier(ulIdValueT);
      pclCanExtP->setIdentifier(ulIdValueT);

      *pclFrameP = *pclCanStdP;
      if(ulIdValueT <= 0x07FF)
      {
         QVERIFY(pclCanStdP->identifier() == ulIdValueT);
         QVERIFY(pclFrameP->identifier()  == ulIdValueT);
      }
      else
      {
         QVERIFY(pclCanStdP->identifier() == (ulIdValueT & 0x07FF));
         QVERIFY(pclFrameP->identifier()  == (ulIdValueT & 0x07FF));
      }
      QVERIFY(pclCanExtP->identifier() == ulIdValueT);

      QVERIFY(pclCanStdP->isExtended() == 0);
      QVERIFY(pclFrameP->isExtended()  == 0);
   }
}

//----------------------------------------------------------------------------//
// checkFrameDlc()                                                            //
// check frame DLC                                                            //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkFrameDlc()
{
   uint8_t  ubSizeT;

   //----------------------------------------------------------------
   // Test 1: set the DLC value for classic CAN and CAN FD and
   // check the result for the dataSize() return
   //
   for(ubSizeT = 0; ubSizeT < 16; ubSizeT++)
   {
      pclCanStdP->setDlc(ubSizeT);
      pclFdStdP->setDlc(ubSizeT);

      //--------------------------------------------------------
      // check data size
      //
      if(ubSizeT < 9)
      {
         QVERIFY(pclCanStdP->dataSize() == ubSizeT);
         QVERIFY(pclFdStdP->dataSize() == ubSizeT);
      }
      else
      {
         //------------------------------------------------
         // copy FD frame contents and convert type to
         // classic CAN
         //
         *pclFrameP = *pclFdStdP;
         pclFrameP->setFrameType(QCanFrame::eTYPE_CAN_STD);

         //------------------------------------------------
         // make sure maximum dataSize of classic CAN is 8
         //
         QVERIFY(pclFrameP->dataSize()  == 8);
         QVERIFY(pclCanStdP->dataSize() == 8);

         //------------------------------------------------
         // check data size of CAN FD
         //
         switch(ubSizeT)
         {
            case 9:
               QVERIFY(pclFdStdP->dataSize() == 12);
               break;

            case 10:
               QVERIFY(pclFdStdP->dataSize() == 16);
               break;

            case 11:
               QVERIFY(pclFdStdP->dataSize() == 20);
               break;

            case 12:
               QVERIFY(pclFdStdP->dataSize() == 24);
               break;

            case 13:
               QVERIFY(pclFdStdP->dataSize() == 32);
               break;

            case 14:
               QVERIFY(pclFdStdP->dataSize() == 48);
               break;

            case 15:
               QVERIFY(pclFdStdP->dataSize() == 64);
               break;

            default:

               break;
         }
      }

      //--------------------------------------------------------
      // check DLC
      //
      if(ubSizeT < 9)
      {
         QVERIFY(pclCanStdP->dlc() == ubSizeT);
         QVERIFY(pclFdStdP->dlc() == ubSizeT);
      }
      else
      {
         QVERIFY(pclCanStdP->dlc() == 8);
         QVERIFY(pclFdStdP->dlc() == ubSizeT);
      }
   }

   //----------------------------------------------------------------
   // Test 2: set DLC value out of range
   //
   pclCanStdP->setDlc(22);
   pclFdStdP->setDlc(22);
   QVERIFY(pclCanStdP->dlc() <= 8);
   QVERIFY(pclFdStdP->dlc()  <= 15);

}

void TestQCanFrame::checkFrameDataSize()
{
   uint8_t  ubSizeT;

   //----------------------------------------------------------------
   // Test 3: set the data size value for classic CAN and CAN FD and
   // check the result for the dlc() return
   //
   for(ubSizeT = 0; ubSizeT < 70; ubSizeT++)
   {
      pclCanStdP->setDataSize(ubSizeT);
      pclFdStdP->setDataSize(ubSizeT);

   }
}

//----------------------------------------------------------------------------//
// checkFrameData()                                                           //
// check frame data                                                           //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkFrameData()
{
   pclCanStdP->setDlc(4);
   pclCanStdP->CpFrame::setData(0, 0x12);
   pclCanStdP->CpFrame::setData(1, 0x34);
   pclCanStdP->CpFrame::setData(2, 0x56);
   pclCanStdP->CpFrame::setData(3, 0x78);

   QVERIFY(pclCanStdP->dataUInt16(0, 1) == 0x1234);
   QVERIFY(pclCanStdP->dataUInt16(1, 1) == 0x3456);
   QVERIFY(pclCanStdP->dataUInt16(2, 1) == 0x5678);
   QVERIFY(pclCanStdP->dataUInt16(3, 1) == 0x0000);

   QVERIFY(pclCanStdP->dataUInt32(0, 1) == 0x12345678);

   pclCanStdP->setDataUInt16(0, 0xAABB);
   QVERIFY(pclCanStdP->CpFrame::data(0) == 0xBB);
   QVERIFY(pclCanStdP->CpFrame::data(1) == 0xAA);
   QVERIFY(pclCanStdP->dataUInt16(0, 0) == 0xAABB);

}

//----------------------------------------------------------------------------//
// checkFrameRemote()                                                         //
// check remote frame                                                         //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkFrameRemote()
{

}

//----------------------------------------------------------------------------//
// checkFrameData()                                                           //
// check frame data                                                           //
//----------------------------------------------------------------------------//
void TestQCanFrame::checkByteArray()
{
   QByteArray  clByteArrayT;

   for(uint8_t ubCntT = 0; ubCntT < 9; ubCntT++)
   {
      pclCanStdP->setIdentifier(0x301 + ubCntT);
      pclCanStdP->setDlc(ubCntT);
      pclCanStdP->CpFrame::setData(0, ubCntT);
      pclCanStdP->CpFrame::setData(1, 0x10 + ubCntT);
      pclCanStdP->CpFrame::setData(2, 0x20 + ubCntT);
      pclCanStdP->CpFrame::setData(3, 0x30 + ubCntT);
      pclCanStdP->CpFrame::setData(4, 0x40 + ubCntT);
      pclCanStdP->CpFrame::setData(5, 0x50 + ubCntT);
      pclCanStdP->CpFrame::setData(6, 0x60 + ubCntT);
      pclCanStdP->CpFrame::setData(7, 0x70 + ubCntT);

      pclCanStdP->setMarker(0x223344);
      pclCanStdP->setUser(0xAB1023);

      clByteArrayT = pclCanStdP->toByteArray();

      QVERIFY(pclFrameP->fromByteArray(clByteArrayT) == true);

      QVERIFY(pclFrameP->identifier() == (0x301 + ubCntT));
      QVERIFY(pclFrameP->dlc()   == (ubCntT));
      if(ubCntT == 4)
      {
         QVERIFY(pclFrameP->CpFrame::data(0) == (ubCntT));
         QVERIFY(pclFrameP->CpFrame::data(1) == (0x10 + ubCntT));
         QVERIFY(pclFrameP->CpFrame::data(2) == (0x20 + ubCntT));
         QVERIFY(pclFrameP->CpFrame::data(3) == (0x30 + ubCntT));
         QVERIFY(pclFrameP->CpFrame::data(4) == 0);
      }

   }
}

//----------------------------------------------------------------------------//
// cleanupTestCase()                                                          //
// cleanup test cases                                                         //
//----------------------------------------------------------------------------//

void TestQCanFrame::cleanupTestCase()
{
   delete(pclCanStdP);
   delete(pclCanExtP);
   delete(pclFdStdP);
   delete(pclFdExtP);

   delete(pclFrameP);
}

<|endoftext|>


<commit_before>/* Copyright © 2001-2015, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

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

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "headsign_handler.h"
#include "utils/functions.h"

namespace navitia { namespace type {

void HeadsignHandler::change_name_and_register_as_headsign(VehicleJourney& vj,
                                                           const std::string& new_name) {
    std::string prev_name = vj.name;
    vj.name = new_name;
    headsign_mvj[vj.name].insert(vj.meta_vj);
    update_headsign_mvj_after_remove(vj, prev_name);
}

void HeadsignHandler::update_headsign_mvj_after_remove(const VehicleJourney& vj,
                                                       const std::string& removed_headsign) {
    // unregister meta-vj from headsign only if necessary
    auto has_mvj = [&] (const VehicleJourney* it_vj) {return it_vj->meta_vj == vj.meta_vj;};
    if (navitia::contains_if(get_vj_from_headsign(removed_headsign), has_mvj)) {
        return;
    }
    {
        auto it_headsign_mvj = headsign_mvj.find(removed_headsign);
        if (it_headsign_mvj == headsign_mvj.end()) {
            return;
        }
        it_headsign_mvj->second.erase(vj.meta_vj);
        if (it_headsign_mvj->second.empty()) {
            headsign_mvj.erase(it_headsign_mvj);
        }
    }
}

const std::string& HeadsignHandler::get_headsign(const StopTime& stop_time) const{
    // if no headsign map for vj: return name
    if (!navitia::contains(headsign_changes, stop_time.vehicle_journey)) {
        return stop_time.vehicle_journey->name;
    }

    // otherwise use headsign change map
    const auto& map_stop_time_headsign_change =
            headsign_changes.at(stop_time.vehicle_journey);
    uint16_t order_stop_time = stop_time.order();

    // if no headsign change stored: return name
    if (map_stop_time_headsign_change.empty()) {
        return stop_time.vehicle_journey->name;
    }

    // get next change
    auto it_headsign = map_stop_time_headsign_change.upper_bound(order_stop_time);
    // if next change is the first: return name
    if(it_headsign == map_stop_time_headsign_change.begin()) {
        return stop_time.vehicle_journey->name;
    }

    // get previous change and return headsign
    if (it_headsign == map_stop_time_headsign_change.end()) {
        return map_stop_time_headsign_change.rbegin()->second;
    }
    return (--it_headsign)->second;
}

std::set<std::string> HeadsignHandler::get_all_headsigns(const VehicleJourney* vj) {
    std::set<std::string> res;
    const auto& it_changes = headsign_changes.find(vj);
    if (!vj || it_changes == std::end(headsign_changes)) {
        return res;
    }
    for (const auto& change: it_changes->second) {
        //ignore last headsign (vj.name) as it does not concern a stop_time
        if (change.first < vj->stop_time_list.size()) {
            res.insert(change.second);
        }
    }
    return res;
}

bool HeadsignHandler::has_headsign_or_name(const VehicleJourney& vj,
                                           const std::string& headsign) const {
    if (vj.name == headsign) {
        return true;
    }

    const auto it_vj_changes = headsign_changes.find(&vj);
    if (it_vj_changes == headsign_changes.end()) {
        return false;
    }

    auto has_headsign = [&] (const std::pair<uint16_t, std::string>& it_change)
                        {return it_change.second == headsign;};
    if (navitia::contains_if(it_vj_changes->second, has_headsign)) {
        return true;
    }
    return false;
}

std::vector<const VehicleJourney*>
HeadsignHandler::get_vj_from_headsign(const std::string& headsign) const {
    std::vector<const VehicleJourney*> res;
    const auto& it_vj_set = headsign_mvj.find(headsign);
    if (it_vj_set == headsign_mvj.end()) {
        return res;
    }

    for (const MetaVehicleJourney* mvj: it_vj_set->second) {
        for (const auto& vect_vj: {mvj->base_vj, mvj->adapted_vj, mvj->real_time_vj}) {
            for (const VehicleJourney* vj: vect_vj) {
                if (has_headsign_or_name(*vj, headsign)) {
                    res.push_back(vj);
                }
            }
        }
    }
    return res;
}

void HeadsignHandler::affect_headsign_to_stop_time(const StopTime& stop_time,
                                                   const std::string& headsign) {
    const VehicleJourney* vj = stop_time.vehicle_journey;
    assert(navitia::contains_if(get_vj_from_headsign(vj->name),
           [&] (const VehicleJourney* it_vj) {return it_vj->meta_vj == vj->meta_vj;}));
    std::string prev_headsign_for_stop_time = get_headsign(stop_time);
    if (headsign == prev_headsign_for_stop_time) {
        return;
    }

    uint16_t order = stop_time.order();
    auto& vj_headsign_changes = headsign_changes[vj];
    // erase change if exists
    if (navitia::contains(vj_headsign_changes, order)) {
        vj_headsign_changes.erase(order);
    }
    // only if headsign erase is not enough: store change
    if (get_headsign(stop_time) != headsign) {
        vj_headsign_changes[order] = headsign;
    }
    // if next stop_time's value is prev_headsign_for_stop_time: store the change back to this
    // previous headsign. Done even if last, as we could add stop_time in the future
    if (!navitia::contains(vj_headsign_changes, order + 1)) {
        vj_headsign_changes[order + 1] = prev_headsign_for_stop_time;
    }
    // if next stop_time changed to  headsign: erase mext change to merge
    else if(vj_headsign_changes[order + 1] == headsign) {
        vj_headsign_changes.erase(order + 1);
    }
    // if map for this vj is empty (all headsigns == vj.name): clean map
    if (vj_headsign_changes.empty()) {
        headsign_changes.erase(vj);
    }

    // register meta-vj from headsign
    headsign_mvj[headsign].insert(vj->meta_vj);
    update_headsign_mvj_after_remove(*vj, prev_headsign_for_stop_time);
}

}} //namespace navitia::type
<commit_msg>ed2nav: optimisation in headsign handler<commit_after>/* Copyright © 2001-2015, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

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

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
IRC #navitia on freenode
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "headsign_handler.h"
#include "utils/functions.h"

namespace navitia { namespace type {

void HeadsignHandler::change_name_and_register_as_headsign(VehicleJourney& vj,
                                                           const std::string& new_name) {
    std::string prev_name = vj.name;
    vj.name = new_name;
    headsign_mvj[vj.name].insert(vj.meta_vj);
    update_headsign_mvj_after_remove(vj, prev_name);
}

void HeadsignHandler::update_headsign_mvj_after_remove(const VehicleJourney& vj,
                                                       const std::string& removed_headsign) {
    // unregister meta-vj from headsign only if necessary
    auto has_mvj = [&] (const VehicleJourney* it_vj) {return it_vj->meta_vj == vj.meta_vj;};
    if (navitia::contains_if(get_vj_from_headsign(removed_headsign), has_mvj)) {
        return;
    }
    {
        auto it_headsign_mvj = headsign_mvj.find(removed_headsign);
        if (it_headsign_mvj == headsign_mvj.end()) {
            return;
        }
        it_headsign_mvj->second.erase(vj.meta_vj);
        if (it_headsign_mvj->second.empty()) {
            headsign_mvj.erase(it_headsign_mvj);
        }
    }
}

const std::string& HeadsignHandler::get_headsign(const StopTime& stop_time) const{
    // if no headsign map for vj: return name
    if (!navitia::contains(headsign_changes, stop_time.vehicle_journey)) {
        return stop_time.vehicle_journey->name;
    }

    // otherwise use headsign change map
    const auto& map_stop_time_headsign_change =
            headsign_changes.at(stop_time.vehicle_journey);
    uint16_t order_stop_time = stop_time.order();

    // if no headsign change stored: return name
    if (map_stop_time_headsign_change.empty()) {
        return stop_time.vehicle_journey->name;
    }

    // get next change
    auto it_headsign = map_stop_time_headsign_change.upper_bound(order_stop_time);
    // if next change is the first: return name
    if(it_headsign == map_stop_time_headsign_change.begin()) {
        return stop_time.vehicle_journey->name;
    }

    // get previous change and return headsign
    if (it_headsign == map_stop_time_headsign_change.end()) {
        return map_stop_time_headsign_change.rbegin()->second;
    }
    return (--it_headsign)->second;
}

std::set<std::string> HeadsignHandler::get_all_headsigns(const VehicleJourney* vj) {
    std::set<std::string> res;
    const auto& it_changes = headsign_changes.find(vj);
    if (!vj || it_changes == std::end(headsign_changes)) {
        return res;
    }
    for (const auto& change: it_changes->second) {
        //ignore last headsign (vj.name) as it does not concern a stop_time
        if (change.first < vj->stop_time_list.size()) {
            res.insert(change.second);
        }
    }
    return res;
}

bool HeadsignHandler::has_headsign_or_name(const VehicleJourney& vj,
                                           const std::string& headsign) const {
    if (vj.name == headsign) {
        return true;
    }

    const auto it_vj_changes = headsign_changes.find(&vj);
    if (it_vj_changes == headsign_changes.end()) {
        return false;
    }

    auto has_headsign = [&] (const std::pair<uint16_t, std::string>& it_change)
                        {return it_change.second == headsign;};
    if (navitia::contains_if(it_vj_changes->second, has_headsign)) {
        return true;
    }
    return false;
}

std::vector<const VehicleJourney*>
HeadsignHandler::get_vj_from_headsign(const std::string& headsign) const {
    std::vector<const VehicleJourney*> res;
    const auto& it_vj_set = headsign_mvj.find(headsign);
    if (it_vj_set == headsign_mvj.end()) {
        return res;
    }

    for (const MetaVehicleJourney* mvj: it_vj_set->second) {
        for (const std::vector<navitia::type::VehicleJourney*>& vect_vj:
                {std::ref(mvj->base_vj), std::ref(mvj->adapted_vj), std::ref(mvj->real_time_vj)}) {
            for (const VehicleJourney* vj: vect_vj) {
                if (has_headsign_or_name(*vj, headsign)) {
                    res.push_back(vj);
                }
            }
        }
    }
    return res;
}

void HeadsignHandler::affect_headsign_to_stop_time(const StopTime& stop_time,
                                                   const std::string& headsign) {
    const VehicleJourney* vj = stop_time.vehicle_journey;
    assert(navitia::contains_if(get_vj_from_headsign(vj->name),
           [&] (const VehicleJourney* it_vj) {return it_vj->meta_vj == vj->meta_vj;}));
    std::string prev_headsign_for_stop_time = get_headsign(stop_time);
    if (headsign == prev_headsign_for_stop_time) {
        return;
    }

    uint16_t order = stop_time.order();
    auto& vj_headsign_changes = headsign_changes[vj];
    // erase change if exists
    if (navitia::contains(vj_headsign_changes, order)) {
        vj_headsign_changes.erase(order);
    }
    // only if headsign erase is not enough: store change
    if (get_headsign(stop_time) != headsign) {
        vj_headsign_changes[order] = headsign;
    }
    // if next stop_time's value is prev_headsign_for_stop_time: store the change back to this
    // previous headsign. Done even if last, as we could add stop_time in the future
    if (!navitia::contains(vj_headsign_changes, order + 1)) {
        vj_headsign_changes[order + 1] = prev_headsign_for_stop_time;
    }
    // if next stop_time changed to  headsign: erase mext change to merge
    else if(vj_headsign_changes[order + 1] == headsign) {
        vj_headsign_changes.erase(order + 1);
    }
    // if map for this vj is empty (all headsigns == vj.name): clean map
    if (vj_headsign_changes.empty()) {
        headsign_changes.erase(vj);
    }

    // register meta-vj from headsign
    headsign_mvj[headsign].insert(vj->meta_vj);
    update_headsign_mvj_after_remove(*vj, prev_headsign_for_stop_time);
}

}} //namespace navitia::type
<|endoftext|>


<commit_before>#ifndef MANIFOLDS_FUNCTIONS_RECIRPOCAL_HH
#define MANIFOLDS_FUNCTIONS_RECIRPOCAL_HH

#include "function.hh"
#include "full_function_defs.hh"

namespace manifolds {
template <class Numerator,
	  class Denominator>
struct DivisionImpl : MultiFunction
{
  static const bool stateless =
    and_<is_stateless<Numerator>,
	 is_stateless<Denominator>>::value;

  DivisionImpl(){}
  DivisionImpl(Numerator n, Denominator d):
    n(n),d(d){}

  template <class ... Args>
  auto operator()(Args ... args) const
  {
    return n(args...) / d(args...);
  }

private:
  Numerator n;
  Denominator d;
};

DEF_FF_TEMPLATE(Division)

}

#endif
<commit_msg>Getters<commit_after>#ifndef MANIFOLDS_FUNCTIONS_RECIRPOCAL_HH
#define MANIFOLDS_FUNCTIONS_RECIRPOCAL_HH

#include "function.hh"
#include "full_function_defs.hh"

namespace manifolds {
template <class Numerator,
	  class Denominator>
struct DivisionImpl : MultiFunction
{
  static const bool stateless =
    and_<is_stateless<Numerator>,
	 is_stateless<Denominator>>::value;

  DivisionImpl(){}
  DivisionImpl(Numerator n, Denominator d):
    n(n),d(d){}

  template <class ... Args>
  auto operator()(Args ... args) const
  {
    return n(args...) / d(args...);
  }

  auto GetNumerator() const
  {
    return n;
  }

  auto GetDenominator() const
  {
    return d;
  }

  auto GetFunctions() const
  {
    return std::make_tuple(n,d);
  }

private:
  Numerator n;
  Denominator d;
};

DEF_FF_TEMPLATE(Division)

}

#endif
<|endoftext|>


<commit_before>// @(#)root/core/meta:$Id$
// Author: Vassil Vassilev   7/10/2012

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

#include "TClingCallbacks.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclBase.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"

using namespace clang;
using namespace cling;

class TObject;

// Functions used to forward calls from code compiled with no-rtti to code
// compiled with rtti.
extern "C" {
   void TCintWithCling__UpdateListsOnCommitted(const cling::Transaction&);
   void TCintWithCling__UpdateListsOnUnloaded(const cling::Transaction&);
   TObject* TCintWithCling__GetObjectAddress(const char *Name, void *&LookupCtx);
   Decl* TCintWithCling__GetObjectDecl(TObject *obj);
   int TCintWithCling__AutoLoadCallback(const char* className);
}

TClingCallbacks::TClingCallbacks(cling::Interpreter* interp)
   : InterpreterCallbacks(interp), fLastLookupCtx(0), fROOTSpecialNamespace(0),
     fFirstRun(true), fIsAutoloading(false), fIsAutoloadingRecursively(false) {
   const Decl* D = 0;
   m_Interpreter->declare("namespace __ROOT_SpecialObjects{}", &D);
   fROOTSpecialNamespace = dyn_cast<NamespaceDecl>(const_cast<Decl*>(D));
}

//pin the vtable here
TClingCallbacks::~TClingCallbacks() {}

// If cling cannot find a name it should ask ROOT before it issues an error.
// If ROOT knows the name then it has to create a new variable with that name
// and type in dedicated for that namespace (eg. __ROOT_SpecialObjects).
// For example if the interpreter is looking for h in h-Draw(), this routine
// will create
// namespace __ROOT_SpecialObjects {
//   THist* h = (THist*) the_address;
// }
//
// Later if h is called again it again won't be found by the standart lookup
// because it is in our hidden namespace (nobody should do using namespace
// __ROOT_SpecialObjects). It caches the variable declarations and their
// last address. If the newly found decl with the same name (h) has different
// address than the cached one it goes directly at the address and updates it.
//
// returns true when declaration is found and no error should be emitted.
bool TClingCallbacks::LookupObject(LookupResult &R, Scope *S) {

   if (tryAutoloadInternal(R, S))
      return true; // happiness.

   // If the autoload wasn't successful try ROOT specials.
   return tryFindROOTSpecialInternal(R, S);
}

bool TClingCallbacks::tryAutoloadInternal(LookupResult &R, Scope *S) {
   Sema &SemaR = m_Interpreter->getSema();
   ASTContext& C = SemaR.getASTContext();
   Preprocessor &PP = SemaR.getPreprocessor();
   DeclarationName Name = R.getLookupName();

   // Try to autoload first if autoloading is enabled
   if (IsAutoloadingEnabled()) {
     // Avoid tail chasing.
     if (fIsAutoloadingRecursively)
       return false;
     fIsAutoloadingRecursively = true;

     // Save state of the PP
     Preprocessor::CleanupAndRestoreCacheRAII cleanupRAII(PP);
     Parser& P = const_cast<Parser&>(m_Interpreter->getParser());
     Parser::ParserCurTokRestoreRAII savedCurToken(P);

     bool oldSuppressDiags = SemaR.getDiagnostics().getSuppressAllDiagnostics();
     SemaR.getDiagnostics().setSuppressAllDiagnostics();

     // We can't PushDeclContext, because we go up and the routine that pops
     // the DeclContext assumes that we drill down always.
     // We have to be on the global context. At that point we are in a
     // wrapper function so the parent context must be the global.
     Sema::ContextAndScopeRAII pushedSAndDC(SemaR, C.getTranslationUnitDecl(),
                                            SemaR.TUScope);

     bool lookupSuccess = false;
     if (TCintWithCling__AutoLoadCallback(Name.getAsString().c_str())) {
       pushedSAndDC.pop();
       cleanupRAII.pop();
       lookupSuccess = SemaR.LookupName(R, S);
     }

     SemaR.getDiagnostics().setSuppressAllDiagnostics(oldSuppressDiags);

     fIsAutoloadingRecursively = false;

     if (lookupSuccess)
       return true;
   }

}

// If cling cannot find a name it should ask ROOT before it issues an error.
// If ROOT knows the name then it has to create a new variable with that name
// and type in dedicated for that namespace (eg. __ROOT_SpecialObjects).
// For example if the interpreter is looking for h in h-Draw(), this routine
// will create
// namespace __ROOT_SpecialObjects {
//   THist* h = (THist*) the_address;
// }
//
// Later if h is called again it again won't be found by the standart lookup
// because it is in our hidden namespace (nobody should do using namespace
// __ROOT_SpecialObjects). It caches the variable declarations and their
// last address. If the newly found decl with the same name (h) has different
// address than the cached one it goes directly at the address and updates it.
//
// returns true when declaration is found and no error should be emitted.
//
bool TClingCallbacks::tryFindROOTSpecialInternal(LookupResult &R, Scope *S) {

   Sema &SemaR = m_Interpreter->getSema();
   ASTContext& C = SemaR.getASTContext();
   Preprocessor &PP = SemaR.getPreprocessor();
   DeclContext *CurDC = SemaR.CurContext;
   DeclarationName Name = R.getLookupName();

   // Make sure that the failed lookup comes from the prompt.
   if(!CurDC || !CurDC->isFunctionOrMethod())
      return false;
   if (NamedDecl* ND = dyn_cast<NamedDecl>(CurDC))
      if (!m_Interpreter->isUniqueWrapper(ND->getNameAsString()))
         return false;

   TObject *obj = TCintWithCling__GetObjectAddress(Name.getAsString().c_str(),
                                                   fLastLookupCtx);
   if (obj) {
      NamedDecl *ND = utils::Lookup::Named(&SemaR, Name, fROOTSpecialNamespace);
      if (ND) {
         TObject **address = (TObject**)m_Interpreter->getAddressOfGlobal(ND);
         // Since code was generated already we cannot rely on the initializer
         // of the decl in the AST, however we will update that init so that it
         // will be easier while debugging.
         VarDecl *VD = cast<VarDecl>(ND);
         CStyleCastExpr *CStyleCast = cast<CStyleCastExpr>(VD->getInit());
         Expr* newInit = utils::Synthesize::IntegerLiteralExpr(C, (uint64_t)obj);
         CStyleCast->setSubExpr(newInit);

         // The actual update happens here, directly in memory.
         *address = obj;
         R.addDecl(ND);
         //TODO: Check for same types.
      }
      else {
         // Save state of the PP
         Preprocessor::CleanupAndRestoreCacheRAII cleanupRAII(PP);

         const Decl *TD = TCintWithCling__GetObjectDecl(obj);
         // We will declare the variable as pointer.
         QualType QT = C.getPointerType(C.getTypeDeclType(cast<TypeDecl>(TD)));

         VarDecl *VD = VarDecl::Create(C, fROOTSpecialNamespace,
                                       SourceLocation(), SourceLocation(),
                                       Name.getAsIdentifierInfo(), QT,
                                       /*TypeSourceInfo*/0, SC_None, SC_None
                                       );
         // Build an initializer
         Expr* Init
           = utils::Synthesize::CStyleCastPtrExpr(&SemaR, QT, (uint64_t)obj);
         // Register the decl in our hidden special namespace
         VD->setInit(Init);
         fROOTSpecialNamespace->addDecl(VD);

         cling::CompilationOptions CO;
         CO.DeclarationExtraction = 0;
         CO.ValuePrinting = CompilationOptions::VPDisabled;
         CO.ResultEvaluation = 0;
         CO.DynamicScoping = 0;
         CO.Debug = 0;
         CO.CodeGeneration = 1;

         cling::Transaction T(CO, /*llvm::Module=*/0);
         T.appendUnique(VD);
         T.setCompleted();

         Interpreter::CompilationResult Result = m_Interpreter->codegen(&T);
         assert(Result == Interpreter::kSuccess
                && "Compilation should never fail!");
         R.addDecl(VD);
      }
      return true;
   }

   return false;
}
// The callback is used to update the list of globals in ROOT.
//
void TClingCallbacks::TransactionCommitted(const Transaction &T) {
   if (!T.size())
      return;
   if (fFirstRun) {
      // Before setting up the callbacks register what cling have seen during init.
      const cling::Transaction* T = m_Interpreter->getFirstTransaction();
      while (T) {
         if (T->getState() == cling::Transaction::kCommitted)
            TCintWithCling__UpdateListsOnCommitted(*T);
         T = T->getNext();
      }

      fFirstRun = false;
   }

   TCintWithCling__UpdateListsOnCommitted(T);
}

// The callback is used to update the list of globals in ROOT.
//
void TClingCallbacks::TransactionUnloaded(const Transaction &T) {
   if (!T.size())
      return;

   TCintWithCling__UpdateListsOnUnloaded(T);
}
<commit_msg>Extract common code.<commit_after>// @(#)root/core/meta:$Id$
// Author: Vassil Vassilev   7/10/2012

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

#include "TClingCallbacks.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclBase.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"

using namespace clang;
using namespace cling;

class TObject;

// Functions used to forward calls from code compiled with no-rtti to code
// compiled with rtti.
extern "C" {
   void TCintWithCling__UpdateListsOnCommitted(const cling::Transaction&);
   void TCintWithCling__UpdateListsOnUnloaded(const cling::Transaction&);
   TObject* TCintWithCling__GetObjectAddress(const char *Name, void *&LookupCtx);
   Decl* TCintWithCling__GetObjectDecl(TObject *obj);
   int TCintWithCling__AutoLoadCallback(const char* className);
}

TClingCallbacks::TClingCallbacks(cling::Interpreter* interp)
   : InterpreterCallbacks(interp), fLastLookupCtx(0), fROOTSpecialNamespace(0),
     fFirstRun(true), fIsAutoloading(false), fIsAutoloadingRecursively(false) {
   const Decl* D = 0;
   m_Interpreter->declare("namespace __ROOT_SpecialObjects{}", &D);
   fROOTSpecialNamespace = dyn_cast<NamespaceDecl>(const_cast<Decl*>(D));
}

//pin the vtable here
TClingCallbacks::~TClingCallbacks() {}

// If cling cannot find a name it should ask ROOT before it issues an error.
// If ROOT knows the name then it has to create a new variable with that name
// and type in dedicated for that namespace (eg. __ROOT_SpecialObjects).
// For example if the interpreter is looking for h in h-Draw(), this routine
// will create
// namespace __ROOT_SpecialObjects {
//   THist* h = (THist*) the_address;
// }
//
// Later if h is called again it again won't be found by the standart lookup
// because it is in our hidden namespace (nobody should do using namespace
// __ROOT_SpecialObjects). It caches the variable declarations and their
// last address. If the newly found decl with the same name (h) has different
// address than the cached one it goes directly at the address and updates it.
//
// returns true when declaration is found and no error should be emitted.
bool TClingCallbacks::LookupObject(LookupResult &R, Scope *S) {

   if (tryAutoloadInternal(R, S))
      return true; // happiness.

   // If the autoload wasn't successful try ROOT specials.
   return tryFindROOTSpecialInternal(R, S);
}

bool TClingCallbacks::tryAutoloadInternal(LookupResult &R, Scope *S) {
   Sema &SemaR = m_Interpreter->getSema();
   ASTContext& C = SemaR.getASTContext();
   Preprocessor &PP = SemaR.getPreprocessor();
   DeclarationName Name = R.getLookupName();

   // Try to autoload first if autoloading is enabled
   if (IsAutoloadingEnabled()) {
     // Avoid tail chasing.
     if (fIsAutoloadingRecursively)
       return false;
     fIsAutoloadingRecursively = true;

     // Save state of the PP
     Preprocessor::CleanupAndRestoreCacheRAII cleanupRAII(PP);
     Parser& P = const_cast<Parser&>(m_Interpreter->getParser());
     Parser::ParserCurTokRestoreRAII savedCurToken(P);

     bool oldSuppressDiags = SemaR.getDiagnostics().getSuppressAllDiagnostics();
     SemaR.getDiagnostics().setSuppressAllDiagnostics();

     // We can't PushDeclContext, because we go up and the routine that pops
     // the DeclContext assumes that we drill down always.
     // We have to be on the global context. At that point we are in a
     // wrapper function so the parent context must be the global.
     Sema::ContextAndScopeRAII pushedSAndDC(SemaR, C.getTranslationUnitDecl(),
                                            SemaR.TUScope);

     bool lookupSuccess = false;
     if (TCintWithCling__AutoLoadCallback(Name.getAsString().c_str())) {
       pushedSAndDC.pop();
       cleanupRAII.pop();
       lookupSuccess = SemaR.LookupName(R, S);
     }

     SemaR.getDiagnostics().setSuppressAllDiagnostics(oldSuppressDiags);

     fIsAutoloadingRecursively = false;

     if (lookupSuccess)
       return true;
   }

}

// If cling cannot find a name it should ask ROOT before it issues an error.
// If ROOT knows the name then it has to create a new variable with that name
// and type in dedicated for that namespace (eg. __ROOT_SpecialObjects).
// For example if the interpreter is looking for h in h-Draw(), this routine
// will create
// namespace __ROOT_SpecialObjects {
//   THist* h = (THist*) the_address;
// }
//
// Later if h is called again it again won't be found by the standart lookup
// because it is in our hidden namespace (nobody should do using namespace
// __ROOT_SpecialObjects). It caches the variable declarations and their
// last address. If the newly found decl with the same name (h) has different
// address than the cached one it goes directly at the address and updates it.
//
// returns true when declaration is found and no error should be emitted.
//
bool TClingCallbacks::tryFindROOTSpecialInternal(LookupResult &R, Scope *S) {

   Sema &SemaR = m_Interpreter->getSema();
   ASTContext& C = SemaR.getASTContext();
   Preprocessor &PP = SemaR.getPreprocessor();
   DeclContext *CurDC = SemaR.CurContext;
   DeclarationName Name = R.getLookupName();

   // Make sure that the failed lookup comes from the prompt.
   if(!CurDC || !CurDC->isFunctionOrMethod())
      return false;
   if (NamedDecl* ND = dyn_cast<NamedDecl>(CurDC))
      if (!m_Interpreter->isUniqueWrapper(ND->getNameAsString()))
         return false;

   TObject *obj = TCintWithCling__GetObjectAddress(Name.getAsString().c_str(),
                                                   fLastLookupCtx);
   if (obj) {
     VarDecl *VD = cast_or_null<VarDecl>(utils::Lookup::Named(&SemaR,
                                                              Name,
                                                        fROOTSpecialNamespace));
      if (VD) {
         //TODO: Check for same types.

         TObject **address = (TObject**)m_Interpreter->getAddressOfGlobal(VD);
         // Since code was generated already we cannot rely on the initializer
         // of the decl in the AST, however we will update that init so that it
         // will be easier while debugging.
         CStyleCastExpr *CStyleCast = cast<CStyleCastExpr>(VD->getInit());
         Expr* newInit = utils::Synthesize::IntegerLiteralExpr(C, (uint64_t)obj);
         CStyleCast->setSubExpr(newInit);

         // The actual update happens here, directly in memory.
         *address = obj;
      }
      else {
         // Save state of the PP
         Preprocessor::CleanupAndRestoreCacheRAII cleanupRAII(PP);

         const Decl *TD = TCintWithCling__GetObjectDecl(obj);
         // We will declare the variable as pointer.
         QualType QT = C.getPointerType(C.getTypeDeclType(cast<TypeDecl>(TD)));

         VD = VarDecl::Create(C, fROOTSpecialNamespace, SourceLocation(),
                              SourceLocation(), Name.getAsIdentifierInfo(), QT,
                              /*TypeSourceInfo*/0, SC_None, SC_None
                              );
         // Build an initializer
         Expr* Init
           = utils::Synthesize::CStyleCastPtrExpr(&SemaR, QT, (uint64_t)obj);
         // Register the decl in our hidden special namespace
         VD->setInit(Init);
         fROOTSpecialNamespace->addDecl(VD);

         cling::CompilationOptions CO;
         CO.DeclarationExtraction = 0;
         CO.ValuePrinting = CompilationOptions::VPDisabled;
         CO.ResultEvaluation = 0;
         CO.DynamicScoping = 0;
         CO.Debug = 0;
         CO.CodeGeneration = 1;

         cling::Transaction T(CO, /*llvm::Module=*/0);
         T.appendUnique(VD);
         T.setCompleted();

         Interpreter::CompilationResult Result = m_Interpreter->codegen(&T);
         assert(Result == Interpreter::kSuccess
                && "Compilation should never fail!");
      }
      assert(VD && "Cannot be null!");
      R.addDecl(VD);
      return true;
   }

   return false;
}
// The callback is used to update the list of globals in ROOT.
//
void TClingCallbacks::TransactionCommitted(const Transaction &T) {
   if (!T.size())
      return;
   if (fFirstRun) {
      // Before setting up the callbacks register what cling have seen during init.
      const cling::Transaction* T = m_Interpreter->getFirstTransaction();
      while (T) {
         if (T->getState() == cling::Transaction::kCommitted)
            TCintWithCling__UpdateListsOnCommitted(*T);
         T = T->getNext();
      }

      fFirstRun = false;
   }

   TCintWithCling__UpdateListsOnCommitted(T);
}

// The callback is used to update the list of globals in ROOT.
//
void TClingCallbacks::TransactionUnloaded(const Transaction &T) {
   if (!T.size())
      return;

   TCintWithCling__UpdateListsOnUnloaded(T);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, Hernan Saez
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> 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 "Rendering/RenderPass.hpp"
#include "Rendering/Renderer.hpp"
#include "Rendering/RenderQueue.hpp"

#include "SceneGraph/Geometry.hpp"

#include "Components/RenderStateComponent.hpp"

#include "Primitives/QuadPrimitive.hpp"

#include "Foundation/Log.hpp"
#include "Foundation/Profiler.hpp"

using namespace crimild;

RenderPass::RenderPass( void )
    : _screen( crimild::alloc< QuadPrimitive >( 2.0f, 2.0f, VertexFormat::VF_P3_UV2, Vector2f( 0.0f, 1.0f ), Vector2f( 1.0f, -1.0f ) ) ),
      _imageEffects( crimild::alloc< SharedObjectList< ImageEffect >>() )
{

}

RenderPass::~RenderPass( void )
{

}

void RenderPass::render( RendererPtr const &renderer, RenderQueuePtr const &renderQueue, CameraPtr const &camera )
{
    renderOpaqueObjects( renderer, renderQueue, camera );
    renderTranslucentObjects( renderer, renderQueue, camera );
    renderScreenObjects( renderer, renderQueue, camera );
}

void RenderPass::render( SharedPointer< Renderer > const &renderer, RenderQueuePtr const &renderQueue, CameraPtr const &camera, RenderQueue::MaterialMap const &objects )
{
    const Matrix4f &projection = camera->getProjectionMatrix();
    const Matrix4f &view = camera->getViewMatrix();

    renderQueue->each( objects, [&]( MaterialPtr const &material, RenderQueue::PrimitiveMap const &primitives ) {
        auto program = material->getProgram() ? material->getProgram() : renderer->getShaderProgram( "phong" );
        if ( program == nullptr ) {
            Log::Error << "No valid program for batch" << Log::End;
            return;
        }

        // bind program
        renderer->bindProgram( program );

        // bind lights
        renderQueue->each( [&]( LightPtr const &light, int ) {
            renderer->bindLight( program, light );
        });

        // bind material properties
        renderer->bindMaterial( program, material );

        for ( auto primitiveIt : primitives ) {
            auto primitive = primitiveIt.first;

            // bind vertex and index buffers
            renderer->bindVertexBuffer( program, primitive->getVertexBuffer() );
            renderer->bindIndexBuffer( program, primitive->getIndexBuffer() );

            for ( auto geometryIt : primitiveIt.second ) {
                Matrix4f model = geometryIt.second.computeModelMatrix();
                Matrix4f normal = model;
                normal[ 12 ] = 0.0f;
                normal[ 13 ] = 0.0f;
                normal[ 14 ] = 0.0f;

                renderer->applyTransformations( program, projection, view, model, normal );
                renderer->drawPrimitive( program, primitive );
            }

            // unbind primitive buffers
            renderer->unbindVertexBuffer( program, primitive->getVertexBuffer() );
            renderer->unbindIndexBuffer( program, primitive->getIndexBuffer() );
        }

        // unbind material properties
        renderer->unbindMaterial( program, material );

        // unbind lights
        renderQueue->each( [&]( LightPtr const &light, int ) {
            renderer->unbindLight( program, light );
        });

        // unbind program
        renderer->unbindProgram( program );
    });
}

void RenderPass::render( RendererPtr const &renderer, TexturePtr const &texture, ShaderProgramPtr const &defaultProgram )
{
    auto program = defaultProgram;
    if ( program == nullptr ) {
        program = renderer->getFallbackProgram( nullptr, nullptr, nullptr );
        if ( program == nullptr ) {
            return;
        }
    }

    // bind shader program first
    renderer->bindProgram( program );

    // bind framebuffer texture
    renderer->bindTexture( program->getStandardLocation( ShaderProgram::StandardLocation::MATERIAL_COLOR_MAP_UNIFORM ), texture );

    // bind vertex and index buffers
    renderer->bindVertexBuffer( program, _screen->getVertexBuffer() );
    renderer->bindIndexBuffer( program, _screen->getIndexBuffer() );

    Matrix4f mMatrix;
    mMatrix.makeIdentity();
    renderer->bindUniform( program->getStandardLocation( ShaderProgram::StandardLocation::MODEL_MATRIX_UNIFORM ), mMatrix );

    // draw primitive
    renderer->drawPrimitive( program, _screen );

    // unbind primitive buffers
    renderer->unbindVertexBuffer( program, _screen->getVertexBuffer() );
    renderer->unbindIndexBuffer( program, _screen->getIndexBuffer() );

    // unbind framebuffer texture
    renderer->unbindTexture( program->getStandardLocation( ShaderProgram::StandardLocation::MATERIAL_COLOR_MAP_UNIFORM ), texture );

    // lastly, unbind the shader program
    renderer->unbindProgram( program );
}

void RenderPass::renderOpaqueObjects( RendererPtr const &renderer, RenderQueuePtr const &renderQueue, CameraPtr const &camera )
{
    CRIMILD_PROFILE( "Render Opaque Objects" )

    render( renderer, renderQueue, camera, renderQueue->getOpaqueObjects() );
}

void RenderPass::renderTranslucentObjects( RendererPtr const &renderer, RenderQueuePtr const &renderQueue, CameraPtr const &camera )
{
    CRIMILD_PROFILE( "Render Translucent Objects" )

    render( renderer, renderQueue, camera, renderQueue->getTranslucentObjects() );
}

void RenderPass::renderScreenObjects( RendererPtr const &renderer, RenderQueuePtr const &renderQueue, CameraPtr const &camera )
{
    CRIMILD_PROFILE( "Render Screen Objects" )

    const Matrix4f &projection = camera->getOrthographicMatrix();
    Matrix4f view;
    view.makeIdentity();

    renderQueue->each( renderQueue->getScreenObjects(), [&]( MaterialPtr const &material, RenderQueue::PrimitiveMap const &primitives ) {
        auto program = material->getProgram() ? material->getProgram() : renderer->getShaderProgram( "phong" );
        if ( program == nullptr ) {
            Log::Error << "No valid program for batch" << Log::End;
            return;
        }

        // bind program
        renderer->bindProgram( program );

        // bind lights
        renderQueue->each( [&]( LightPtr const &light, int ) {
            renderer->bindLight( program, light );
        });

        // bind material properties
        renderer->bindMaterial( program, material );

        for ( auto it : primitives ) {
            auto primitive = it.first;

            // bind vertex and index buffers
            renderer->bindVertexBuffer( program, primitive->getVertexBuffer() );
            renderer->bindIndexBuffer( program, primitive->getIndexBuffer() );

            for ( auto geometryIt : it.second ) {
                auto model = geometryIt.second.computeModelMatrix();
                auto normal = model;
                normal[ 12 ] = 0.0f;
                normal[ 13 ] = 0.0f;
                normal[ 14 ] = 0.0f;

                renderer->applyTransformations( program, projection, view, model, normal );
                renderer->drawPrimitive( program, primitive );
            }

            // unbind primitive buffers
            renderer->unbindVertexBuffer( program, primitive->getVertexBuffer() );
            renderer->unbindIndexBuffer( program, primitive->getIndexBuffer() );
        }

        // unbind material properties
        renderer->unbindMaterial( program, material );

        // unbind lights
        renderQueue->each( [&]( LightPtr const &light, int ) {
            renderer->unbindLight( program, light );
        });

        // unbind program
        renderer->unbindProgram( program );
    });

}

<commit_msg>RenderPass now uses right projection and view matrices for rendering<commit_after>/*
 * Copyright (c) 2013, Hernan Saez
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> 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 "Rendering/RenderPass.hpp"
#include "Rendering/Renderer.hpp"
#include "Rendering/RenderQueue.hpp"

#include "SceneGraph/Geometry.hpp"

#include "Components/RenderStateComponent.hpp"

#include "Primitives/QuadPrimitive.hpp"

#include "Foundation/Log.hpp"
#include "Foundation/Profiler.hpp"

using namespace crimild;

RenderPass::RenderPass( void )
    : _screen( crimild::alloc< QuadPrimitive >( 2.0f, 2.0f, VertexFormat::VF_P3_UV2, Vector2f( 0.0f, 1.0f ), Vector2f( 1.0f, -1.0f ) ) ),
      _imageEffects( crimild::alloc< SharedObjectList< ImageEffect >>() )
{

}

RenderPass::~RenderPass( void )
{

}

void RenderPass::render( RendererPtr const &renderer, RenderQueuePtr const &renderQueue, CameraPtr const &camera )
{
    renderOpaqueObjects( renderer, renderQueue, camera );
    renderTranslucentObjects( renderer, renderQueue, camera );
    renderScreenObjects( renderer, renderQueue, camera );
}

void RenderPass::render( SharedPointer< Renderer > const &renderer, RenderQueuePtr const &renderQueue, CameraPtr const &camera, RenderQueue::MaterialMap const &objects )
{
    const Matrix4f &projection = renderQueue->getProjectionMatrix();
    const Matrix4f &view = renderQueue->getViewMatrix();

    renderQueue->each( objects, [&]( MaterialPtr const &material, RenderQueue::PrimitiveMap const &primitives ) {
        auto program = material->getProgram() ? material->getProgram() : renderer->getShaderProgram( "phong" );
        if ( program == nullptr ) {
            Log::Error << "No valid program for batch" << Log::End;
            return;
        }

        // bind program
        renderer->bindProgram( program );

        // bind lights
        renderQueue->each( [&]( LightPtr const &light, int ) {
            renderer->bindLight( program, light );
        });

        // bind material properties
        renderer->bindMaterial( program, material );

        for ( auto primitiveIt : primitives ) {
            auto primitive = primitiveIt.first;

            // bind vertex and index buffers
            renderer->bindVertexBuffer( program, primitive->getVertexBuffer() );
            renderer->bindIndexBuffer( program, primitive->getIndexBuffer() );

            for ( auto geometryIt : primitiveIt.second ) {
                Matrix4f model = geometryIt.second.computeModelMatrix();
                Matrix4f normal = model;
                normal[ 12 ] = 0.0f;
                normal[ 13 ] = 0.0f;
                normal[ 14 ] = 0.0f;

                renderer->applyTransformations( program, projection, view, model, normal );
                renderer->drawPrimitive( program, primitive );
            }

            // unbind primitive buffers
            renderer->unbindVertexBuffer( program, primitive->getVertexBuffer() );
            renderer->unbindIndexBuffer( program, primitive->getIndexBuffer() );
        }

        // unbind material properties
        renderer->unbindMaterial( program, material );

        // unbind lights
        renderQueue->each( [&]( LightPtr const &light, int ) {
            renderer->unbindLight( program, light );
        });

        // unbind program
        renderer->unbindProgram( program );
    });
}

void RenderPass::render( RendererPtr const &renderer, TexturePtr const &texture, ShaderProgramPtr const &defaultProgram )
{
    auto program = defaultProgram;
    if ( program == nullptr ) {
        program = renderer->getFallbackProgram( nullptr, nullptr, nullptr );
        if ( program == nullptr ) {
            return;
        }
    }

    // bind shader program first
    renderer->bindProgram( program );

    // bind framebuffer texture
    renderer->bindTexture( program->getStandardLocation( ShaderProgram::StandardLocation::MATERIAL_COLOR_MAP_UNIFORM ), texture );

    // bind vertex and index buffers
    renderer->bindVertexBuffer( program, _screen->getVertexBuffer() );
    renderer->bindIndexBuffer( program, _screen->getIndexBuffer() );

    Matrix4f mMatrix;
    mMatrix.makeIdentity();
    renderer->bindUniform( program->getStandardLocation( ShaderProgram::StandardLocation::MODEL_MATRIX_UNIFORM ), mMatrix );

    // draw primitive
    renderer->drawPrimitive( program, _screen );

    // unbind primitive buffers
    renderer->unbindVertexBuffer( program, _screen->getVertexBuffer() );
    renderer->unbindIndexBuffer( program, _screen->getIndexBuffer() );

    // unbind framebuffer texture
    renderer->unbindTexture( program->getStandardLocation( ShaderProgram::StandardLocation::MATERIAL_COLOR_MAP_UNIFORM ), texture );

    // lastly, unbind the shader program
    renderer->unbindProgram( program );
}

void RenderPass::renderOpaqueObjects( RendererPtr const &renderer, RenderQueuePtr const &renderQueue, CameraPtr const &camera )
{
    CRIMILD_PROFILE( "Render Opaque Objects" )

    render( renderer, renderQueue, camera, renderQueue->getOpaqueObjects() );
}

void RenderPass::renderTranslucentObjects( RendererPtr const &renderer, RenderQueuePtr const &renderQueue, CameraPtr const &camera )
{
    CRIMILD_PROFILE( "Render Translucent Objects" )

    render( renderer, renderQueue, camera, renderQueue->getTranslucentObjects() );
}

void RenderPass::renderScreenObjects( RendererPtr const &renderer, RenderQueuePtr const &renderQueue, CameraPtr const &camera )
{
    CRIMILD_PROFILE( "Render Screen Objects" )

    const Matrix4f &projection = camera->getOrthographicMatrix();
    Matrix4f view;
    view.makeIdentity();

    renderQueue->each( renderQueue->getScreenObjects(), [&]( MaterialPtr const &material, RenderQueue::PrimitiveMap const &primitives ) {
        auto program = material->getProgram() ? material->getProgram() : renderer->getShaderProgram( "phong" );
        if ( program == nullptr ) {
            Log::Error << "No valid program for batch" << Log::End;
            return;
        }

        // bind program
        renderer->bindProgram( program );

        // bind lights
        renderQueue->each( [&]( LightPtr const &light, int ) {
            renderer->bindLight( program, light );
        });

        // bind material properties
        renderer->bindMaterial( program, material );

        for ( auto it : primitives ) {
            auto primitive = it.first;

            // bind vertex and index buffers
            renderer->bindVertexBuffer( program, primitive->getVertexBuffer() );
            renderer->bindIndexBuffer( program, primitive->getIndexBuffer() );

            for ( auto geometryIt : it.second ) {
                auto model = geometryIt.second.computeModelMatrix();
                auto normal = model;
                normal[ 12 ] = 0.0f;
                normal[ 13 ] = 0.0f;
                normal[ 14 ] = 0.0f;

                renderer->applyTransformations( program, projection, view, model, normal );
                renderer->drawPrimitive( program, primitive );
            }

            // unbind primitive buffers
            renderer->unbindVertexBuffer( program, primitive->getVertexBuffer() );
            renderer->unbindIndexBuffer( program, primitive->getIndexBuffer() );
        }

        // unbind material properties
        renderer->unbindMaterial( program, material );

        // unbind lights
        renderQueue->each( [&]( LightPtr const &light, int ) {
            renderer->unbindLight( program, light );
        });

        // unbind program
        renderer->unbindProgram( program );
    });

}

<|endoftext|>


<commit_before><commit_msg>Fix caret bounds to use min of available height and font height.<commit_after><|endoftext|>