text:
/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include "bgp/peer_close_manager.h"

#include <list>
#include <map>

#include <boost/foreach.hpp>

#include "base/task_annotations.h"
#include "bgp/bgp_log.h"
#include "bgp/bgp_membership.h"
#include "bgp/bgp_peer_types.h"
#include "bgp/bgp_route.h"
#include "bgp/bgp_server.h"
#include "bgp/routing-instance/routing_instance.h"
#include "net/community_type.h"

#define PEER_CLOSE_MANAGER_LOG(msg) \
    BGP_LOG_PEER(Event, peer_close_->peer(), SandeshLevel::SYS_INFO,           \
        BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,                                     \
        "PeerCloseManager: State " << GetStateName(state_) <<                  \
        ", MembershipState: " << GetMembershipStateName(membership_state_) <<  \
        ", MembershipReqPending: " << membership_req_pending_ <<               \
        ", CloseAgain?: " << (close_again_ ? "Yes" : "No") << ": " << msg);

#define PEER_CLOSE_MANAGER_TABLE_LOG(msg)                                      \
    BGP_LOG_PEER_TABLE(peer_close_->peer(), SandeshLevel::SYS_INFO,            \
        BGP_LOG_FLAG_ALL, table,                                               \
        "PeerCloseManager: State " << GetStateName(state_) <<                  \
        ", MembershipState: " << GetMembershipStateName(membership_state_) <<  \
        ", MembershipReqPending: " << membership_req_pending_ <<               \
        ", CloseAgain?: " << (close_again_ ? "Yes" : "No") << ": " << msg);

#define MOVE_TO_STATE(state)                                                   \
    do {                                                                       \
        assert(state_ != state);                                               \
        PEER_CLOSE_MANAGER_LOG("Move to state " << GetStateName(state));       \
        state_ = state;                                                        \
    } while (false)

// Create an instance of PeerCloseManager with back reference to parent IPeer
PeerCloseManager::PeerCloseManager(IPeerClose *peer_close,
                                   boost::asio::io_service *io_service) :
        peer_close_(peer_close), gr_timer_(NULL),
        event_queue_(new WorkQueue<Event *>(
                     TaskScheduler::GetInstance()->GetTaskId(
                         peer_close_->GetTaskName()),
                     peer_close_->GetTaskInstance(),
                     boost::bind(&PeerCloseManager::EventCallback, this, _1))),
        state_(NONE), close_again_(false), graceful_(true), gr_elapsed_(0),
        llgr_elapsed_(0), membership_state_(MEMBERSHIP_NONE) {
    stats_.init++;
    membership_req_pending_ = 0;
    gr_timer_ = TimerManager::CreateTimer(*io_service,
                                          "Graceful Restart Timer");
}

// Create an instance of PeerCloseManager with back reference to parent IPeer
PeerCloseManager::PeerCloseManager(IPeerClose *peer_close) :
        peer_close_(peer_close), gr_timer_(NULL),
        event_queue_(new WorkQueue<Event *>(
                     TaskScheduler::GetInstance()->GetTaskId(
                         peer_close_->GetTaskName()),
                     peer_close_->GetTaskInstance(),
                     boost::bind(&PeerCloseManager::EventCallback, this, _1))),
        state_(NONE), close_again_(false), graceful_(true), gr_elapsed_(0),
        llgr_elapsed_(0), membership_state_(MEMBERSHIP_NONE) {
    stats_.init++;
    membership_req_pending_ = 0;
    if (peer_close->peer() && peer_close->peer()->server()) {
        gr_timer_ =
           TimerManager::CreateTimer(*peer_close->peer()->server()->ioservice(),
                                     "Graceful Restart Timer");
    }
}

PeerCloseManager::~PeerCloseManager() {
    event_queue_->Shutdown();
    TimerManager::DeleteTimer(gr_timer_);
}

std::string PeerCloseManager::GetStateName(State state) const {
    switch (state) {
    case NONE:
        return "NONE";
    case GR_TIMER:
        return "GR_TIMER";
    case STALE:
        return "STALE";
    case LLGR_STALE:
        return "LLGR_STALE";
    case LLGR_TIMER:
        return "LLGR_TIMER";
    case SWEEP:
        return "SWEEP";
    case DELETE:
        return "DELETE";
    }
    assert(false);
    return "";
}

std::string PeerCloseManager::GetMembershipStateName(
        MembershipState state) const {
    switch (state) {
    case MEMBERSHIP_NONE:
        return "NONE";
    case MEMBERSHIP_IN_USE:
        return "IN_USE";
    case MEMBERSHIP_IN_WAIT:
        return "IN_WAIT";
    }
    assert(false);
    return "";
}

std::string PeerCloseManager::GetEventName(EventType eventType) const {
    switch (eventType) {
    case EVENT_NONE:
        return "NONE";
    case CLOSE:
        return "CLOSE";
    case EOR_RECEIVED:
        return "EOR_RECEIVED";
    case MEMBERSHIP_REQUEST:
        return "MEMBERSHIP_REQUEST";
    case MEMBERSHIP_REQUEST_COMPLETE_CALLBACK:
        return "MEMBERSHIP_REQUEST_COMPLETE_CALLBACK";
    case TIMER_CALLBACK:
        return "TIMER_CALLBACK";
    }

    return "";
}

void PeerCloseManager::EnqueueEvent(Event *event) {
    PEER_CLOSE_MANAGER_LOG("Enqueued event " <<
            GetEventName(event->event_type) <<
            ", graceful " << event->graceful <<
            ", family " << Address::FamilyToString(event->family));
    event_queue_->Enqueue(event);
}

// Trigger closure of an IPeer
//
// Graceful                                 close_state_: NONE
// RibIn Stale Marking and Ribout deletion  close_state_: STALE
// StateMachine restart and GR timer start  close_state_: GR_TIMER
//
// Peer IsReady() in GR timer callback (or via reception of all EoRs)
// RibIn Sweep and Ribout Generation        close_state_: SWEEP
//   MembershipRequestCallback      close_state_: NONE
//
// Peer not IsReady() in GR timer callback
// If LLGR supported                     close_state_: LLGR_STALE
//   RibIn Stale marking with LLGR_STALE community close_state_: LLGR_TIMER
//
//     Peer not IsReady() in LLGR timer callback
//       RibIn Delete                       close_state_: DELETE
//       MembershipRequestCallback                 close_state_: NONE
//
//     Peer IsReady() in LLGR timer callback (or via reception of all EoRs)
//     RibIn Sweep                          close_state_: SWEEP
//       MembershipRequestCallback  close_state_: NONE
//
// If LLGR is not supported
//     RibIn Delete                         close_state_: DELETE
//     MembershipRequestCallback    close_state_: NONE
//
// Close() call during any state other than NONE and DELETE
//     Cancel GR timer and restart GR Closure all over again
//
// NonGraceful                              close_state_ = * (except DELETE)
// A. RibIn deletion and Ribout deletion    close_state_ = DELETE
// B. MembershipRequestCallback => Peers delete/StateMachine restart
//                                          close_state_ = NONE
//
// If Close is restarted, account for GR timer's elapsed time.
//
// Use graceful as true to close gracefully.
void PeerCloseManager::Close(bool graceful) {
    EnqueueEvent(new Event(CLOSE, graceful));
}

void PeerCloseManager::Close(Event *event) {
    // Note down non-graceful close trigger. Once non-graceful closure is
    // triggered, it should remain so until close process is complete. Further
    // graceful closure calls until then should remain non-graceful.
    graceful_ &= event->graceful;
    CloseInternal();
}

void PeerCloseManager::CloseInternal() {
    stats_.close++;

    // Ignore nested closures
    if (close_again_) {
        PEER_CLOSE_MANAGER_LOG("Nested close calls ignored");
        return;
    }

    switch (state_) {
    case NONE:
        stats_.ResetRouteStats();
        ProcessClosure();
        break;

    case GR_TIMER:
        PEER_CLOSE_MANAGER_LOG("Nested close: Restart GR");
        close_again_ = true;
        stats_.nested++;
        gr_elapsed_ += gr_timer_->GetElapsedTime();
        CloseComplete();
        break;

    case LLGR_TIMER:
        PEER_CLOSE_MANAGER_LOG("Nested close: Restart LLGR");
        close_again_ = true;
        stats_.nested++;
        llgr_elapsed_ += gr_timer_->GetElapsedTime();
        CloseComplete();
        break;

    case STALE:
    case LLGR_STALE:
    case SWEEP:
    case DELETE:
        PEER_CLOSE_MANAGER_LOG("Nested close");
        close_again_ = true;
        stats_.nested++;
        break;
    }
}

void PeerCloseManager::ProcessEORMarkerReceived(Address::Family family) {
    EnqueueEvent(new Event(EOR_RECEIVED, family));
}

void PeerCloseManager::ProcessEORMarkerReceived(Event *event) {
    if ((state_ == GR_TIMER || state_ == LLGR_TIMER) && !families_.empty()) {
        if (event->family == Address::UNSPEC) {
            families_.clear();
        } else {
            families_.erase(event->family);
        }

        // Start the timer if all EORs have been received.
        if (families_.empty())
            StartRestartTimer(0);
    }
}

// Process RibIn during peer closure.
void PeerCloseManager::StartRestartTimer(int time) {
    gr_timer_->Cancel();
    PEER_CLOSE_MANAGER_LOG("GR Timer started to fire after " << time/1000 <<
                           " seconds");
    gr_timer_->Start(time,
        boost::bind(&PeerCloseManager::RestartTimerCallback, this));
}

bool PeerCloseManager::RestartTimerCallback() {
    CHECK_CONCURRENCY("timer::TimerTask");
    EnqueueEvent(new Event(TIMER_CALLBACK));
    return false;
}

void PeerCloseManager::RestartTimerCallback(Event *event) {
    CHECK_CONCURRENCY(peer_close_->GetTaskName());

    PEER_CLOSE_MANAGER_LOG("GR Timer callback started");
    if (state_ != GR_TIMER && state_ != LLGR_TIMER)
        return;

    if (peer_close_->IsReady() && !families_.empty()) {
        // Fake reception of all EORs.
        for (IPeerClose::Families::iterator i = families_.begin(), next = i;
                i != families_.end(); i = next) {
            next++;
            PEER_CLOSE_MANAGER_LOG("Simulate EoR reception for family " << *i);
            peer_close_->ReceiveEndOfRIB(*i);
        }
    } else {
        ProcessClosure();
    }
}

// Route stale timer callback. If the peer has come back up, sweep routes for
// those address families that are still active. Delete the rest
void PeerCloseManager::ProcessClosure() {
    // If the peer is back up and this address family is still supported,
    // sweep old paths which may not have come back in the new session
    switch (state_) {
        case NONE:
            if (!graceful_ || !peer_close_->IsCloseGraceful()) {
                MOVE_TO_STATE(DELETE);
                stats_.deletes++;
            } else {
                MOVE_TO_STATE(STALE);
                stats_.stale++;
                StaleNotify();
                return;
            }
            break;
        case GR_TIMER:
            if (peer_close_->IsReady()) {
                MOVE_TO_STATE(SWEEP);
                gr_elapsed_ = 0;
                llgr_elapsed_ = 0;
                stats_.sweep++;
                break;
            }
            if (peer_close_->IsCloseLongLivedGraceful()) {
                MOVE_TO_STATE(LLGR_STALE);
                stats_.llgr_stale++;
                peer_close_->LongLivedGracefulRestartStale();
                break;
            }
            MOVE_TO_STATE(DELETE);
            stats_.deletes++;
            break;

        case LLGR_TIMER:
            if (peer_close_->IsReady()) {
                MOVE_TO_STATE(SWEEP);
                gr_elapsed_ = 0;
                llgr_elapsed_ = 0;
                stats_.sweep++;
                break;
            }
            MOVE_TO_STATE(DELETE);
            stats_.deletes++;
            break;

        case STALE:
        case LLGR_STALE:
        case SWEEP:
        case DELETE:
            assert(false);
            return;
    }

    if (state_ == DELETE)
        peer_close_->CustomClose();
    MembershipRequest();
}

void PeerCloseManager::CloseComplete() {
    MOVE_TO_STATE(NONE);
    gr_timer_->Cancel();
    families_.clear();
    stats_.init++;

    // Nested closures trigger fresh GR
    if (close_again_) {
        close_again_ = false;
        CloseInternal();
    }
}

bool PeerCloseManager::AssertSweepState(bool do_assert) {
    bool check = (state_ == SWEEP);
    if (do_assert)
        assert(check);
    return check;
}

bool PeerCloseManager::AssertMembershipManagerInUse(bool do_assert) {
    bool check = false;
    check |= (state_ == STALE || state_ == LLGR_STALE || state_ == SWEEP ||
              state_ == DELETE);
    check |= (membership_state_ == MEMBERSHIP_IN_USE);
    check |= (membership_req_pending_ > 0);
    if (do_assert)
        assert(check);
    return check;
}

bool PeerCloseManager::AssertMembershipState(bool do_assert) {
    bool check = (membership_state_ != MEMBERSHIP_IN_USE);
    if (do_assert)
        assert(check);
    return check;
}

bool PeerCloseManager::AssertMembershipReqCount(bool do_assert) {
    bool check = !membership_req_pending_;
    if (do_assert)
        assert(check);
    return check;
}

void PeerCloseManager::TriggerSweepStateActions() {
    CHECK_CONCURRENCY(peer_close_->GetTaskName());
    if (!AssertSweepState())
        return;

    // Notify clients to trigger sweep as appropriate.
    peer_close_->GracefulRestartSweep();

    // Reset MembershipUse state after client has been notified above.
    set_membership_state(MEMBERSHIP_NONE);
    CloseComplete();
}

// Notify clients about entering Stale event.
void PeerCloseManager::StaleNotify() {
    CHECK_CONCURRENCY(peer_close_->GetTaskName());

    peer_close_->GracefulRestartStale();
    if (!AssertMembershipState())
        return;
    MembershipRequest(NULL);
}

bool PeerCloseManager::CanUseMembershipManager() const {
    return peer_close_->peer()->CanUseMembershipManager();
}

void PeerCloseManager::GetRegisteredRibs(std::list<BgpTable *> *tables) {
    BgpMembershipManager *mgr = peer_close_->peer()->server()->membership_mgr();
    mgr->GetRegisteredRibs(peer_close_->peer(), tables);
}

bool PeerCloseManager::IsRegistered(BgpTable *table) const {
    BgpMembershipManager *mgr = peer_close_->peer()->server()->membership_mgr();
    return mgr->IsRegistered(peer_close_->peer(), table);
}

void PeerCloseManager::Unregister(BgpTable *table) {
    BgpMembershipManager *mgr = peer_close_->peer()->server()->membership_mgr();
    mgr->Unregister(peer_close_->peer(), table);
}

void PeerCloseManager::WalkRibIn(BgpTable *table) {
    BgpMembershipManager *mgr = peer_close_->peer()->server()->membership_mgr();
    mgr->WalkRibIn(peer_close_->peer(), table);
}

void PeerCloseManager::UnregisterRibOut(BgpTable *table) {
    BgpMembershipManager *mgr = peer_close_->peer()->server()->membership_mgr();
    mgr->UnregisterRibOut(peer_close_->peer(), table);
}

bool PeerCloseManager::IsRibInRegistered(BgpTable *table) const {
    BgpMembershipManager *mgr = peer_close_->peer()->server()->membership_mgr();
    return mgr->IsRibInRegistered(peer_close_->peer(), table);
}

void PeerCloseManager::UnregisterRibIn(BgpTable *table) {
    BgpMembershipManager *mgr = peer_close_->peer()->server()->membership_mgr();
    mgr->UnregisterRibIn(peer_close_->peer(), table);
}

void PeerCloseManager::MembershipRequest() {
    if (!AssertMembershipState())
        return;

    // Pause if membership manager is not ready for usage.
    if (!CanUseMembershipManager()) {
        set_membership_state(MEMBERSHIP_IN_WAIT);
        PEER_CLOSE_MANAGER_LOG("Wait for membership manager availability");
        return;
    }
    set_membership_state(MEMBERSHIP_IN_USE);
    EnqueueEvent(new Event(MEMBERSHIP_REQUEST));
}

void PeerCloseManager::MembershipRequest(Event *evnet) {
    CHECK_CONCURRENCY(peer_close_->GetTaskName());

    set_membership_state(MEMBERSHIP_IN_USE);
    if (!AssertMembershipReqCount())
        return;
    membership_req_pending_++;
    std::list<BgpTable *> tables;
    GetRegisteredRibs(&tables);

    if (tables.empty()) {
        assert(MembershipRequestCallback(NULL));
        return;
    }

    // Account for extra increment above.
    membership_req_pending_--;
    BOOST_FOREACH(BgpTable *table, tables) {
        membership_req_pending_++;
        if (IsRegistered(table)) {
            if (state_ == PeerCloseManager::DELETE) {
                PEER_CLOSE_MANAGER_TABLE_LOG(
                    "MembershipManager::Unregister");
                Unregister(table);
            } else if (state_ == PeerCloseManager::SWEEP) {
                PEER_CLOSE_MANAGER_TABLE_LOG("MembershipManager::WalkRibIn");
                WalkRibIn(table);
            } else {
                PEER_CLOSE_MANAGER_TABLE_LOG(
                    "MembershipManager::UnregisterRibOut");
                UnregisterRibOut(table);
            }
        } else {
            assert(IsRibInRegistered(table));
            if (state_ == PeerCloseManager::DELETE) {
                PEER_CLOSE_MANAGER_TABLE_LOG(
                    "MembershipManager::UnregisterRibIn");
                UnregisterRibIn(table);
            } else {
                PEER_CLOSE_MANAGER_TABLE_LOG("MembershipManager::WalkRibIn");
                WalkRibIn(table);
            }
        }
    }
}

void PeerCloseManager::MembershipRequestCallback() {
    EnqueueEvent(new Event(MEMBERSHIP_REQUEST_COMPLETE_CALLBACK));
}

// Close process for this peer in terms of walking RibIns and RibOuts are
// complete. Do the final cleanups necessary and notify interested party
//
// Retrun true if we are done using membership manager, false otherwise.
bool PeerCloseManager::MembershipRequestCallback(Event *event) {
    CHECK_CONCURRENCY(peer_close_->GetTaskName());

    bool result = false;
    PEER_CLOSE_MANAGER_LOG("MembershipRequestCallback");

    if (!AssertMembershipManagerInUse())
        return result;
    if (--membership_req_pending_)
        return result;

    // Indicate to the caller that we are done using the membership manager.
    result = true;

    if (state_ == DELETE) {
        MOVE_TO_STATE(NONE);
        peer_close_->Delete();
        gr_elapsed_ = 0;
        llgr_elapsed_ = 0;
        stats_.init++;
        close_again_ = false;
        graceful_ = true;
        set_membership_state(MEMBERSHIP_NONE);
        return result;
    }

    // Process nested closures.
    if (close_again_) {
        set_membership_state(MEMBERSHIP_NONE);
        CloseComplete();

        // Nested closure can make membership manager to be in use again.
        return membership_state_ != MEMBERSHIP_IN_USE;
    }

    // If any GR stale timer has to be launched, then to wait for some time
    // hoping for the peer (and the paths) to come back up.
    if (state_ == STALE) {
        peer_close_->CloseComplete();
        MOVE_TO_STATE(GR_TIMER);
        peer_close_->GetGracefulRestartFamilies(&families_);

        // Offset restart time with elapsed time during nested closures.
        int time = peer_close_->GetGracefulRestartTime() * 1000;
        time -= gr_elapsed_;
        if (time < 0)
            time = 0;
        StartRestartTimer(time);
        stats_.gr_timer++;
        set_membership_state(MEMBERSHIP_NONE);
        return result;
    }

    // From LLGR_STALE state, switch to LLGR_TIMER state. Typically this would
    // be a very long timer, and we expect to receive EORs before this timer
    // expires.
    // Just like for GRSTALE in the above case, before moving to LLGR_TIMER and
    // starting LLGR_TIMER, we can check if the peer can come back up.
    if (state_ == LLGR_STALE) {
        MOVE_TO_STATE(LLGR_TIMER);
        peer_close_->CloseComplete();
        peer_close_->GetLongLivedGracefulRestartFamilies(&families_);

        // Offset restart time with elapsed time during nested closures.
        int time = peer_close_->GetLongLivedGracefulRestartTime() * 1000;
        time -= llgr_elapsed_;
        if (time < 0)
            time = 0;
        StartRestartTimer(time);
        stats_.llgr_timer++;
        set_membership_state(MEMBERSHIP_NONE);
        return result;
    }

    TriggerSweepStateActions();
    return result;
}

void PeerCloseManager::FillRouteCloseInfo(PeerCloseInfo *close_info) const {
    std::map<std::string, PeerCloseRouteInfo> route_stats;

    for (int i = 0; i < Address::NUM_FAMILIES; i++) {
        if (!stats_.route_stats[i].IsSet())
            continue;
        PeerCloseRouteInfo route_info;
        route_info.set_staled(stats_.route_stats[i].staled);
        route_info.set_llgr_staled(stats_.route_stats[i].llgr_staled);
        route_info.set_refreshed(stats_.route_stats[i].refreshed);
        route_info.set_fresh(stats_.route_stats[i].fresh);
        route_info.set_deleted(stats_.route_stats[i].deleted);
        route_stats[Address::FamilyToString(static_cast<Address::Family>(i))] =
            route_info;
    }

    if (!route_stats.empty())
        close_info->set_route_stats(route_stats);
}

BgpNeighborResp *PeerCloseManager::FillCloseInfo(BgpNeighborResp *resp) const {
    PeerCloseInfo peer_close_info;
    peer_close_info.set_state(GetStateName(state_));
    peer_close_info.set_membership_state(
        GetMembershipStateName(membership_state_));
    peer_close_info.set_close_again(close_again_);
    peer_close_info.set_graceful(graceful_);
    peer_close_info.set_init(stats_.init);
    peer_close_info.set_close(stats_.close);
    peer_close_info.set_nested(stats_.nested);
    peer_close_info.set_deletes(stats_.deletes);
    peer_close_info.set_stale(stats_.stale);
    peer_close_info.set_llgr_stale(stats_.llgr_stale);
    peer_close_info.set_sweep(stats_.sweep);
    peer_close_info.set_gr_timer(stats_.gr_timer);
    peer_close_info.set_llgr_timer(stats_.llgr_timer);
    FillRouteCloseInfo(&peer_close_info);

    resp->set_peer_close_info(peer_close_info);

    return resp;
}

void PeerCloseManager::UpdateRouteStats(Address::Family family,
        const BgpPath *old_path, uint32_t path_flags) const {
    if (state_ == NONE)
        return;

    if (!old_path)
        stats_.route_stats[family].fresh++;
    else if (old_path->IsStale() && !(path_flags & BgpPath::Stale))
        stats_.route_stats[family].refreshed++;
}

bool PeerCloseManager::MembershipPathCallback(DBTablePartBase *root,
                                              BgpRoute *rt, BgpPath *path) {
    CHECK_CONCURRENCY("db::DBTable");
    DBRequest::DBOperation oper = DBRequest::DB_ENTRY_INVALID;
    BgpAttrPtr attrs;

    BgpTable *table = static_cast<BgpTable *>(root->parent());
    assert(table);

    uint32_t stale = 0;

    switch (state_) {
        case NONE:
        case GR_TIMER:
        case LLGR_TIMER:
            return false;

        case SWEEP:

            // Stale paths must be deleted.
            if (!path->IsStale() && !path->IsLlgrStale())
                return false;
            if (path->IsStale()) {
                path->ResetStale();
                table->UpdateStalePathCount(-1);
            }
            if (path->IsLlgrStale()) {
                path->ResetLlgrStale();
                table->UpdateLlgrStalePathCount(-1);
            }
            oper = DBRequest::DB_ENTRY_DELETE;
            attrs = NULL;
            stats_.route_stats[table->family()].deleted++;
            break;

        case DELETE:

            // This path must be deleted. Hence attr is not required.
            oper = DBRequest::DB_ENTRY_DELETE;
            attrs = NULL;
            stats_.route_stats[table->family()].deleted++;
            break;

        case STALE:

            // We do not support GR for multicast routes (yet).
            if ((table->family() == Address::ERMVPN) ||
                    (table->family() == Address::MVPN)) {
                oper = DBRequest::DB_ENTRY_DELETE;
                attrs = NULL;
                stats_.route_stats[table->family()].deleted++;
                break;
            }

            // If path is already marked as stale, then there is no need to
            // process again. This can happen if the session flips while in
            // GR_TIMER state.
            if (path->IsStale())
                return false;

            // This path must be marked for staling. Update the local
            // preference and update the route accordingly.
            oper = DBRequest::DB_ENTRY_ADD_CHANGE;
            attrs = path->GetAttr();
            stale = BgpPath::Stale;
            stats_.route_stats[table->family()].staled++;
            break;

        case LLGR_STALE:

            // If the path has NO_LLGR community, DELETE it.
            if (path->GetAttr()->community() &&
                path->GetAttr()->community()->ContainsValue(
                    CommunityType::NoLlgr)) {
                oper = DBRequest::DB_ENTRY_DELETE;
                attrs = NULL;
                stats_.route_stats[table->family()].deleted++;
                break;
            }

            // If path is already marked as llgr_stale, then there is no
            // need to process again. This can happen if the session flips
            // while in LLGR_TIMER state.
            if (path->IsLlgrStale())
                return false;

            attrs = path->GetAttr();
            stale = BgpPath::LlgrStale;
            oper = DBRequest::DB_ENTRY_ADD_CHANGE;
            stats_.route_stats[table->family()].llgr_staled++;
            break;
    }

    // Feed the route modify/delete request to the table input process.
    return table->InputCommon(root, rt, path, peer_close_->peer(), NULL, oper,
        attrs, path->GetPathId(), path->GetFlags() | stale, path->GetLabel(),
        path->GetL3Label());
}

//
// Handler for an Event.
//
bool PeerCloseManager::EventCallback(Event *event) {
    CHECK_CONCURRENCY(peer_close_->GetTaskName());
    bool result;

    switch (event->event_type) {
    case EVENT_NONE:
        break;
    case CLOSE:
        Close(event);
        break;
    case EOR_RECEIVED:
        ProcessEORMarkerReceived(event);
        break;
    case MEMBERSHIP_REQUEST:
        MembershipRequest(event);
        break;
    case MEMBERSHIP_REQUEST_COMPLETE_CALLBACK:
        result = MembershipRequestCallback(event);

        // Notify clients if we are no longer using the membership mgr.
        if (result)
            peer_close_->MembershipRequestCallbackComplete();
        break;
    case TIMER_CALLBACK:
        RestartTimerCallback(event);
        break;
    }

    delete event;
    return true;
}

ext: cc

max_stars_repo_name: EWERK-DIGITAL/tf-controller

max_issues_repo_name: EWERK-DIGITAL/tf-controller

max_forks_repo_name: EWERK-DIGITAL/tf-controller


text:
#include <grit.h>
#include <glue.h>  // needed for svg_draw
#include <util.h>  // needed for util::get_data_file_path

#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/test_tools.hpp>

inline void test_data(std::string const & txt_filename)
{
  grit::engine2d_type  engine;
  grit::param_type     parameters;

  std::string const full_filename =  util::get_data_file_path(txt_filename);

  BOOST_CHECK_NO_THROW( grit::init_engine_with_mesh_file(full_filename,parameters,engine) );

  {
    std::string const svg_filename = full_filename + ".svg";
    std::vector<unsigned int> labels;
    grit::compute_phase_labels(engine.mesh(), labels);
    for(unsigned int i=0u; i< labels.size();++i)
    {
      parameters.add_label(labels[i]);
    }
    glue::svg_draw(svg_filename, engine, parameters);
  }
}

BOOST_AUTO_TEST_SUITE(grit);

BOOST_AUTO_TEST_CASE(test_mesh_data_files)
{
  test_data( "circle.txt"                     );  // has an ear
  test_data( "crescent.txt"                   );  // has an ear
  test_data( "filled.txt"                     );  // has an ear
  test_data( "filled2.txt"                    );  // has an ear
  test_data( "filled3.txt"                    );  // has an ear
  test_data( "hollow_circle.txt"              );  // has an ear
  test_data( "JeppeSandbox.txt"               );  // has an ear
  test_data( "rectangle.txt"                  );  // has an ear
  test_data( "rectangle_refined.txt"          );  // has an ear
  test_data( "simple_rectangle.txt"           );  // has an ear, has triangles with negative orientation
  test_data( "smaller_circle.txt"             );  // has an ear
  test_data( "small_circle.txt"               );  // has an ear
  test_data( "small_circles.txt"              );  // has an ear
  test_data( "small_circle_larger_domain.txt" );  // has an ear
  test_data( "small_magnets.txt"              );  // has an ear
  test_data( "small_rectangle.txt"            );  // has an ear
  test_data( "small_rectangles.txt"           );  // has an ear
  test_data( "unit_coarse.txt"                );  // has an ear
  test_data( "circle_enright.txt"             );
  test_data( "horseshoe.txt"                  );
  test_data( "magnet.txt"                     );
  test_data( "refined_circle.txt"             );
  test_data( "unit_test.txt"                  );
  test_data( "zalesak.txt"                    );
  test_data( "two_rectangles.txt"             );
  test_data( "breast.msh"                     ); // has triangles with negative orientation
  test_data( "two_rectangles.msh"             );
}

BOOST_AUTO_TEST_SUITE_END();

ext: cpp

max_forks_repo_name: misztal/GRIT


text:
#include "sif/motorscootercost.h"
#include "sif/costconstants.h"

#include <iostream>
#include "midgard/constants.h"
#include "baldr/directededge.h"
#include "baldr/nodeinfo.h"
#include "baldr/accessrestriction.h"
#include "midgard/util.h"

#ifdef INLINE_TEST
#include "test/test.h"
#include <random>
#include <boost/property_tree/json_parser.hpp>
#endif

using namespace valhalla::baldr;

namespace valhalla {
namespace sif {

// Default options/values
namespace {

constexpr float kDefaultManeuverPenalty         = 5.0f;   // Seconds
constexpr float kDefaultDestinationOnlyPenalty  = 600.0f; // Seconds
constexpr float kDefaultAlleyPenalty            = 5.0f;   // Seconds
constexpr float kDefaultGateCost                = 30.0f;  // Seconds
constexpr float kDefaultGatePenalty             = 300.0f; // Seconds
constexpr float kDefaultTollBoothCost           = 15.0f;  // Seconds
constexpr float kDefaultTollBoothPenalty        = 0.0f;   // Seconds
constexpr float kDefaultFerryCost               = 300.0f; // Seconds
constexpr float kDefaultCountryCrossingCost     = 600.0f; // Seconds
constexpr float kDefaultCountryCrossingPenalty  = 0.0f;   // Seconds
constexpr float kDefaultUseFerry                = 0.5f;   // Factor between 0 and 1

constexpr float kDefaultUseHills                = 0.5f;   // Factor between 0 and 1
constexpr float kDefaultUsePrimary              = 0.5f;   // Factor between 0 and 1
constexpr uint32_t kDefaultTopSpeed             = 45;     // Kilometers per hour

constexpr Surface kMinimumScooterSurface = Surface::kCompacted;

// Maximum ferry penalty (when use_ferry == 0). Can't make this too large
// since a ferry is sometimes required to complete a route.
constexpr float kMaxFerryPenalty = 6.0f * kSecPerHour; // 6 hours

// Default turn costs
constexpr float kTCStraight         = 0.5f;
constexpr float kTCSlight           = 0.75f;
constexpr float kTCFavorable        = 1.0f;
constexpr float kTCFavorableSharp   = 1.5f;
constexpr float kTCCrossing         = 2.0f;
constexpr float kTCUnfavorable      = 2.5f;
constexpr float kTCUnfavorableSharp = 3.5f;
constexpr float kTCReverse          = 5.0f;

// How much to favor hov roads.
constexpr float kHOVFactor = 0.85f;

// Turn costs based on side of street driving
constexpr float kRightSideTurnCosts[] = { kTCStraight, kTCSlight,
      kTCFavorable, kTCFavorableSharp, kTCReverse, kTCUnfavorableSharp,
      kTCUnfavorable, kTCSlight };
constexpr float kLeftSideTurnCosts[]  = { kTCStraight, kTCSlight,
      kTCUnfavorable, kTCUnfavorableSharp, kTCReverse, kTCFavorableSharp,
      kTCFavorable, kTCSlight };

// Maximum amount of seconds that will be allowed to be passed in to influence paths
// This can't be too high because sometimes a certain kind of path is required to be taken
constexpr float kMaxSeconds = 12.0f * kSecPerHour; // 12 hours

// Valid ranges and defaults
constexpr ranged_default_t<float> kManeuverPenaltyRange{0, kDefaultManeuverPenalty, kMaxSeconds};
constexpr ranged_default_t<float> kDestinationOnlyPenaltyRange{0, kDefaultDestinationOnlyPenalty, kMaxSeconds};
constexpr ranged_default_t<float> kAlleyPenaltyRange{0, kDefaultAlleyPenalty, kMaxSeconds};
constexpr ranged_default_t<float> kGateCostRange{0, kDefaultGateCost, kMaxSeconds};
constexpr ranged_default_t<float> kGatePenaltyRange{0, kDefaultGatePenalty, kMaxSeconds};
constexpr ranged_default_t<float> kTollBoothCostRange{0, kDefaultTollBoothCost, kMaxSeconds};
constexpr ranged_default_t<float> kTollBoothPenaltyRange{0, kDefaultTollBoothPenalty, kMaxSeconds};
constexpr ranged_default_t<float> kFerryCostRange{0, kDefaultFerryCost, kMaxSeconds};
constexpr ranged_default_t<float> kCountryCrossingCostRange{0, kDefaultCountryCrossingCost, kMaxSeconds};
constexpr ranged_default_t<float> kCountryCrossingPenaltyRange{0, kDefaultCountryCrossingPenalty, kMaxSeconds};
constexpr ranged_default_t<float> kUseFerryRange{0, kDefaultUseFerry, 1.0f};

// Valid ranges and defaults for motorized scooters
constexpr ranged_default_t<float> kUseHillsRange{0, kDefaultUseHills, 1.0f};
constexpr ranged_default_t<float> kUsePrimaryRange{0, kDefaultUsePrimary, 1.0f};
constexpr ranged_default_t<uint32_t> kTopSpeedRange{0, kDefaultTopSpeed, kMaxSpeedKph};

// Weighting factor based on road class. These apply penalties to higher class
// roads. These penalties are modulated by the useroads factor - further
// avoiding higher class roads for those with low propensity for using roads.
constexpr float kRoadClassFactor[] = {
    1.0f,   // Motorway
    0.4f,   // Trunk
    0.2f,   // Primary
    0.1f,   // Secondary
    0.05f,  // Tertiary
    0.05f,  // Unclassified
    0.0f,   // Residential
    0.5f    // Service, other
};

constexpr uint32_t kMaxGradeFactor = 15;

// Avoid hills "strength". How much do we want to avoid a hill. Combines
// with the usehills factor (1.0 - usehills = avoidhills factor) to create
// a weighting penalty per weighted grade factor. This indicates how strongly
// edges with the specified grade are weighted. Note that speed also is
// influenced by grade, so these weights help further avoid hills.
constexpr float kAvoidHillsStrength[] = {
    0.5f,      // -10%  - Treacherous descent possible
    0.4f,      // -8%   - Steep downhill
    0.3f,      // -6.5% - Good downhill - where is the bottom?
    0.2f,      // -5%   - Picking up speed!
    0.1f,      // -3%   - Modest downhill
    0.0f,      // -1.5% - Smooth slight downhill, ride this all day!
    0.05f,     // 0%    - Flat, no avoidance
    0.1f,      // 1.5%  - These are called "false flat"
    0.25f,     // 3%    - Slight rise
    0.5f,      // 5%    - Small hill
    0.75f,     // 6.5%  - Starting to feel this...
    1.25f,     // 8%    - Moderately steep
    2.0f,      // 10%   - Getting tough
    3.0f,      // 11.5% - Tiring!
    4.25f,     // 13%   - Ooof - this hurts
    5.5f       // 15%   - Only for the strongest!
};

constexpr float kSurfaceSpeedFactors[] =
        { 1.0f, 1.0f, 0.9f, 0.6f, 0.0f, 0.0f, 0.0f, 0.0f };

}

/**
 * Derived class providing dynamic edge costing for "direct" auto routes. This
 * is a route that is generally shortest time but uses route hierarchies that
 * can result in slightly longer routes that avoid shortcuts on residential
 * roads.
 */
class MotorScooterCost : public DynamicCost {
 public:
  /**
   * Construct auto costing. Pass in configuration using property tree.
   * @param  config  Property tree with configuration/options.
   */
  //Armin H.
  MotorScooterCost(const boost::property_tree::ptree& config, baldr::GraphReader& graphreader);

  virtual ~MotorScooterCost();

  /**
   * Does the costing method allow multiple passes (with relaxed hierarchy
   * limits).
   * @return  Returns true if the costing model allows multiple passes.
   */
  virtual bool AllowMultiPass() const;

  /**
   * Get the access mode used by this costing method.
   * @return  Returns access mode.
   */
  uint32_t access_mode() const;

  /**
   * Checks if access is allowed for the provided directed edge.
   * This is generally based on mode of travel and the access modes
   * allowed on the edge. However, it can be extended to exclude access
   * based on other parameters.
   * @param  edge     Pointer to a directed edge.
   * @param  pred     Predecessor edge information.
   * @param  tile     current tile
   * @param  edgeid   edgeid that we care about
   * @return  Returns true if access is allowed, false if not.
   */
  virtual bool Allowed(const baldr::DirectedEdge* edge,
                       const EdgeLabel& pred,
                       const baldr::GraphTile*& tile,
                       const baldr::GraphId& edgeid) const;

  /**
   * Checks if access is allowed for an edge on the reverse path
   * (from destination towards origin). Both opposing edges are
   * provided.
   * @param  edge           Pointer to a directed edge.
   * @param  pred           Predecessor edge information.
   * @param  opp_edge       Pointer to the opposing directed edge.
   * @param  tile           Tile for the opposing edge (for looking
   *                        up restrictions).
   * @param  opp_edgeid     Opposing edge Id
   * @return  Returns true if access is allowed, false if not.
   */
  virtual bool AllowedReverse(const baldr::DirectedEdge* edge,
                 const EdgeLabel& pred,
                 const baldr::DirectedEdge* opp_edge,
                 const baldr::GraphTile*& tile,
                 const baldr::GraphId& opp_edgeid) const;

  /**
   * Checks if access is allowed for the provided node. Node access can
   * be restricted if bollards or gates are present.
   * @param  edge  Pointer to node information.
   * @return  Returns true if access is allowed, false if not.
   */
  virtual bool Allowed(const baldr::NodeInfo* node) const;

  /**
   * Get the cost to traverse the specified directed edge. Cost includes
   * the time (seconds) to traverse the edge.
   * @param   edge  Pointer to a directed edge.
   * @return  Returns the cost and time (seconds)
   */
  virtual Cost EdgeCost(const baldr::DirectedEdge* edge) const;

  /**
   * Returns the cost to make the transition from the predecessor edge.
   * Defaults to 0. Costing models that wish to include edge transition
   * costs (i.e., intersection/turn costs) must override this method.
   * @param  edge  Directed edge (the to edge)
   * @param  node  Node (intersection) where transition occurs.
   * @param  pred  Predecessor edge information.
   * @return  Returns the cost and time (seconds)
   */
  virtual Cost TransitionCost(const baldr::DirectedEdge* edge,
                              const baldr::NodeInfo* node,
                              const EdgeLabel& pred) const;

  /**
   * Returns the cost to make the transition from the predecessor edge
   * when using a reverse search (from destination towards the origin).
   * @param  idx   Directed edge local index
   * @param  node  Node (intersection) where transition occurs.
   * @param  pred  the opposing current edge in the reverse tree.
   * @param  edge  the opposing predecessor in the reverse tree
   * @return  Returns the cost and time (seconds)
   */
  virtual Cost TransitionCostReverse(
      const uint32_t idx, const baldr::NodeInfo* node,
      const baldr::DirectedEdge* pred,
      const baldr::DirectedEdge* edge) const;

  /**
   * Get the cost factor for A* heuristics. This factor is multiplied
   * with the distance to the destination to produce an estimate of the
   * minimum cost to the destination. The A* heuristic must underestimate the
   * cost to the destination. So a time based estimate based on speed should
   * assume the maximum speed is used to the destination such that the time
   * estimate is less than the least possible time along roads.
   */
  virtual float AStarCostFactor() const;

  /**
   * Get the current travel type.
   * @return  Returns the current travel type.
   */
  virtual uint8_t travel_type() const;

  /**
   * Returns a function/functor to be used in location searching which will
   * exclude and allow ranking results from the search by looking at each
   * edges attribution and suitability for use as a location by the travel
   * mode used by the costing method. Function/functor is also used to filter
   * edges not usable / inaccessible by automobile.
   */
  virtual const EdgeFilter GetEdgeFilter() const {
    // Throw back a lambda that checks the access for this type of costing
    return [](const baldr::DirectedEdge* edge) {
      if (edge->IsTransition() || edge->is_shortcut() ||
         !(edge->forwardaccess() & kMopedAccess) ||
         edge->surface() > kMinimumScooterSurface)
        return 0.0f;
      else {
        // TODO - use classification/use to alter the factor
        return 1.0f;
      }
    };
  }

  /**
   * Returns a function/functor to be used in location searching which will
   * exclude results from the search by looking at each node's attribution
   * @return Function/functor to be used in filtering out nodes
   */
  virtual const NodeFilter GetNodeFilter() const {
    //throw back a lambda that checks the access for this type of costing
    return [](const baldr::NodeInfo* node){
      return !(node->access() & kMopedAccess);
    };
  }

  // Hidden in source file so we don't need it to be protected
  // We expose it within the source file for testing purposes
 public:
  float speedfactor_[kMaxSpeedKph + 1];
  float density_factor_[16];        // Density factor
  float maneuver_penalty_;          // Penalty (seconds) when inconsistent names
  float destination_only_penalty_;  // Penalty (seconds) using a driveway or parking aisle
  float gate_cost_;                 // Cost (seconds) to go through gate
  float gate_penalty_;              // Penalty (seconds) to go through gate
  float tollbooth_cost_;            // Cost (seconds) to go through toll booth
  float tollbooth_penalty_;         // Penalty (seconds) to go through a toll booth
  float ferry_cost_;                // Cost (seconds) to enter a ferry
  float ferry_penalty_;             // Penalty (seconds) to enter a ferry
  float ferry_factor_;              // Weighting to apply to ferry edges
  float alley_penalty_;             // Penalty (seconds) to use a alley
  float country_crossing_cost_;     // Cost (seconds) to go through toll booth
  float country_crossing_penalty_;  // Penalty (seconds) to go across a country border
  float use_ferry_;

  // Density factor used in edge transition costing
  std::vector<float> trans_density_factor_;

  uint32_t top_speed_;  // Top speed the motorized scooter can go. Used to avoid roads
                        // with higher speeds than it

  float use_hills_;     // Scale from 0 (avoid hills) to 1 (don't avoid hills)
  float use_primary_;   // Scale from 0 (avoid primary roads) to 1 (don't avoid primary roads)

  // Elevation/grade penalty (weighting applied based on the edge's weighted
  // grade (relative value from 0-15)
  float grade_penalty_[16];
};

// Constructor
//Armin H.
MotorScooterCost::MotorScooterCost(const boost::property_tree::ptree& pt, baldr::GraphReader& graphreader)
    : DynamicCost(pt, graphreader, TravelMode::kDrive),
      trans_density_factor_{ 1.0f, 1.0f, 1.0f, 1.0f,
                             1.0f, 1.1f, 1.2f, 1.3f,
                             1.4f, 1.6f, 1.9f, 2.2f,
                             2.5f, 2.8f, 3.1f, 3.5f } {
  maneuver_penalty_ = kManeuverPenaltyRange(
    pt.get<float>("maneuver_penalty", kDefaultManeuverPenalty)
  );
  destination_only_penalty_ = kDestinationOnlyPenaltyRange(
    pt.get<float>("destination_only_penalty", kDefaultDestinationOnlyPenalty)
  );
  gate_cost_ = kGateCostRange(
    pt.get<float>("gate_cost", kDefaultGateCost)
  );
  gate_penalty_ = kGatePenaltyRange(
    pt.get<float>("gate_penalty", kDefaultGatePenalty)
  );
  tollbooth_cost_ = kTollBoothCostRange(
    pt.get<float>("toll_booth_cost", kDefaultTollBoothCost)
  );
  tollbooth_penalty_ = kTollBoothPenaltyRange(
    pt.get<float>("toll_booth_penalty", kDefaultTollBoothPenalty)
  );
  alley_penalty_ = kAlleyPenaltyRange(
    pt.get<float>("alley_penalty", kDefaultAlleyPenalty)
  );
  country_crossing_cost_ = kCountryCrossingCostRange(
    pt.get<float>("country_crossing_cost", kDefaultCountryCrossingCost)
  );
  country_crossing_penalty_ = kCountryCrossingPenaltyRange(
    pt.get<float>("country_crossing_penalty", kDefaultCountryCrossingPenalty)
  );

  // Set the cost (seconds) to enter a ferry (only apply entering since
  // a route must exit a ferry (except artificial test routes ending on
  // a ferry!)
  ferry_cost_ = kFerryCostRange(
    pt.get<float>("ferry_cost", kDefaultFerryCost)
  );

  // Modify ferry penalty and edge weighting based on use_ferry factor
  use_ferry_ = kUseFerryRange(
    pt.get<float>("use_ferry", kDefaultUseFerry)
  );
  if (use_ferry_ < 0.5f) {
    // Penalty goes from max at use_ferry_ = 0 to 0 at use_ferry_ = 0.5
    ferry_penalty_ = static_cast<uint32_t>(kMaxFerryPenalty * (1.0f - use_ferry_ * 2.0f));

    // Cost X10 at use_ferry_ == 0, slopes downwards towards 1.0 at use_ferry_ = 0.5
    ferry_factor_ = 10.0f - use_ferry_ * 18.0f;
  } else {
    // Add a ferry weighting factor to influence cost along ferries to make
    // them more favorable if desired rather than driving. No ferry penalty.
    // Half the cost at use_ferry_ == 1, progress to 1.0 at use_ferry_ = 0.5
    ferry_penalty_ = 0.0f;
    ferry_factor_  = 1.5f - use_ferry_;
  }

  // Create speed cost table
  speedfactor_[0] = kSecPerHour;  // TODO - what to make speed=0?
  for (uint32_t s = 1; s <= kMaxSpeedKph; s++) {
    speedfactor_[s] = (kSecPerHour * 0.001f) / static_cast<float>(s);
  }

  // Set density factors - used to penalize edges in dense, urban areas
  for (uint32_t d = 0; d < 16; d++) {
    density_factor_[d] = 0.85f + (d * 0.025f);
  }

  top_speed_ = kTopSpeedRange (
    pt.get<float>("top_speed", 45)
  );

  use_hills_ = kUseHillsRange (
      pt.get<float>("use_hills", 0.5f)
  );
  use_primary_ = kUsePrimaryRange (
      pt.get<float>("use_primary", 0.5f)
  );

  float avoid_hills = (1.0f - use_hills_);
  for (uint32_t i = 0; i <= kMaxGradeFactor; ++i) {
    grade_penalty_[i] = avoid_hills * kAvoidHillsStrength[i];
  }
}

// Destructor
MotorScooterCost::~MotorScooterCost() {
}

// Does the costing method allow multiple passes (with relaxed hierarchy
// limits).
bool MotorScooterCost::AllowMultiPass() const {
  return true;
}

// Get the access mode for motor scooter
uint32_t MotorScooterCost::access_mode() const {
  return kMopedAccess;
}

// Check if access is allowed on the specified edge.
bool MotorScooterCost::Allowed(const baldr::DirectedEdge* edge,
                     const EdgeLabel& pred,
                     const baldr::GraphTile*& tile,
                     const baldr::GraphId& edgeid) const {
  // Check access, U-turn, and simple turn restriction.
  // Allow U-turns at dead-end nodes.
  if (!(edge->forwardaccess() & kMopedAccess) ||
      (!pred.deadend() && pred.opp_local_idx() == edge->localedgeidx()) ||
      (pred.restrictions() & (1 << edge->localedgeidx())) ||
       IsUserAvoidEdge(edgeid) ||
      (!allow_destination_only_ && !pred.destonly() && edge->destonly())) {
    return false;
  }
  return edge->surface() <= kMinimumScooterSurface;
}

// Checks if access is allowed for an edge on the reverse path (from
// destination towards origin). Both opposing edges are provided.
bool MotorScooterCost::AllowedReverse(const baldr::DirectedEdge* edge,
                             const EdgeLabel& pred,
                             const baldr::DirectedEdge* opp_edge,
                             const baldr::GraphTile*& tile,
                             const baldr::GraphId& opp_edgeid) const {
  // Check access, U-turn, and simple turn restriction.
  // Allow U-turns at dead-end nodes.
  if (!(opp_edge->forwardaccess() & kMopedAccess) ||
       (!pred.deadend() && pred.opp_local_idx() == edge->localedgeidx()) ||
       (opp_edge->restrictions() & (1 << pred.opp_local_idx())) ||
        IsUserAvoidEdge(opp_edgeid) ||
       (!allow_destination_only_ && !pred.destonly() && opp_edge->destonly())) {
    return false;
  }
  return opp_edge->surface() <= kMinimumScooterSurface;
}

// Check if access is allowed at the specified node.
bool MotorScooterCost::Allowed(const baldr::NodeInfo* node) const  {
  return (node->access() & kMopedAccess);
}

Cost MotorScooterCost::EdgeCost(const baldr::DirectedEdge* edge) const {

  if (edge->use() == Use::kFerry) {
    float sec = (edge->length() * speedfactor_[edge->speed()]);
    return {sec * ferry_factor_, sec };
  }

  uint32_t scooter_speed = (std::min(top_speed_, edge->speed ())
    * kSurfaceSpeedFactors[static_cast<uint32_t>(edge->surface())]);

  float speed_penalty = (edge->speed() > top_speed_) ? (edge->speed() - top_speed_) * 0.05f : 0.0f;
  float factor = density_factor_[edge->density()] +
      kRoadClassFactor[static_cast<uint32_t>(edge->classification())] +
      grade_penalty_[static_cast<uint32_t>(edge->weighted_grade())] +
      speed_penalty;

  float sec = (edge->length() * speedfactor_[scooter_speed]);
  return {sec * factor, sec};
}

// Returns the time (in seconds) to make the transition from the predecessor
Cost MotorScooterCost::TransitionCost(const baldr::DirectedEdge* edge,
                              const baldr::NodeInfo* node,
                              const EdgeLabel& pred) const {
  // Accumulate cost and penalty
  float seconds = 0.0f;
  float penalty = 0.0f;

  // Special cases with both time and penalty: country crossing,
  // gate, toll booth
  if (node->type() == NodeType::kBorderControl) {
    seconds += country_crossing_cost_;
    penalty += country_crossing_penalty_;
  } else if (node->type() == NodeType::kGate) {
    seconds += gate_cost_;
    penalty += gate_penalty_;
  }
  if (node->type() == NodeType::kTollBooth ||
     (!pred.toll() && edge->toll())) {
    seconds += tollbooth_cost_;
    penalty += tollbooth_penalty_;
  }

  // Additional penalties without any time cost
  uint32_t idx = pred.opp_local_idx();
  if (allow_destination_only_ && !pred.destonly() && edge->destonly()) {
    penalty += destination_only_penalty_;
  }
  if (pred.use() != Use::kAlley && edge->use() == Use::kAlley) {
    penalty += alley_penalty_;
  }
  if (pred.use() != Use::kFerry && edge->use() == Use::kFerry) {
    seconds += ferry_cost_;
    penalty += ferry_penalty_;
  }
  // Ignore name inconsistency when entering a link to avoid double penalizing.
  if (!edge->link() && !node->name_consistency(idx, edge->localedgeidx())) {
    // Slight maneuver penalty
    penalty += maneuver_penalty_;
  }

  // Transition time = densityfactor * stopimpact * turncost
  if (edge->stopimpact(idx) > 0) {
    float turn_cost;
    if (edge->edge_to_right(idx) && edge->edge_to_left(idx)) {
      turn_cost = kTCCrossing;
    } else {
      turn_cost = (edge->drive_on_right()) ?
          kRightSideTurnCosts[static_cast<uint32_t>(edge->turntype(idx))] :
          kLeftSideTurnCosts[static_cast<uint32_t>(edge->turntype(idx))];
    }
    seconds += trans_density_factor_[node->density()] *
               edge->stopimpact(idx) * turn_cost;
  }

  // Return cost (time and penalty)
  return { seconds + penalty, seconds };
}

// Returns the cost to make the transition from the predecessor edge
// when using a reverse search (from destination towards the origin).
// pred is the opposing current edge in the reverse tree
// edge is the opposing predecessor in the reverse tree
Cost MotorScooterCost::TransitionCostReverse(const uint32_t idx,
                                     const baldr::NodeInfo* node,
                                     const baldr::DirectedEdge* pred,
                                     const baldr::DirectedEdge* edge) const {
  // Accumulate cost and penalty
  float seconds = 0.0f;
  float penalty = 0.0f;

  // Special cases with both time and penalty: country crossing,
  // gate, toll booth
  if (node->type() == NodeType::kBorderControl) {
    seconds += country_crossing_cost_;
    penalty += country_crossing_penalty_;
  } else if (node->type() == NodeType::kGate) {
    seconds += gate_cost_;
    penalty += gate_penalty_;
  }
  if (node->type() == NodeType::kTollBooth ||
     (!pred->toll() && edge->toll())) {
    seconds += tollbooth_cost_;
    penalty += tollbooth_penalty_;
  }

  // Additional penalties without any time cost
  if (allow_destination_only_ && !pred->destonly() && edge->destonly()) {
    penalty += destination_only_penalty_;
  }
  if (pred->use() != Use::kAlley && edge->use() == Use::kAlley) {
    penalty += alley_penalty_;
  }
  if (pred->use() != Use::kFerry && edge->use() == Use::kFerry) {
    seconds += ferry_cost_;
    penalty += ferry_penalty_;
  }
  // Ignore name inconsistency when entering a link to avoid double penalizing.
  if (!edge->link() && !node->name_consistency(idx, edge->localedgeidx())) {
    // Slight maneuver penalty
    penalty += maneuver_penalty_;
  }

  // Transition time = densityfactor * stopimpact * turncost
  if (edge->stopimpact(idx) > 0) {
    float turn_cost;
    if (edge->edge_to_right(idx) && edge->edge_to_left(idx)) {
      turn_cost = kTCCrossing;
    } else {
      turn_cost = (edge->drive_on_right()) ?
          kRightSideTurnCosts[static_cast<uint32_t>(edge->turntype(idx))] :
          kLeftSideTurnCosts[static_cast<uint32_t>(edge->turntype(idx))];
    }
    seconds += trans_density_factor_[node->density()] *
               edge->stopimpact(idx) * turn_cost;
  }

  // Return cost (time and penalty)
  return { seconds + penalty, seconds };
}

// Get the cost factor for A* heuristics. This factor is multiplied
// with the distance to the destination to produce an estimate of the
// minimum cost to the destination. The A* heuristic must underestimate the
// cost to the destination. So a time based estimate based on speed should
// assume the maximum speed is used to the destination such that the time
// estimate is less than the least possible time along roads.
float MotorScooterCost::AStarCostFactor() const {
  return speedfactor_[kMaxSpeedKph];
}

// Returns the current travel type.
uint8_t MotorScooterCost::travel_type() const {
  return static_cast<uint8_t>(VehicleType::kMotorScooter);
}

//Armin H.
cost_ptr_t CreateMotorScooterCost(const boost::property_tree::ptree& config, baldr::GraphReader& graphreader) {
  return std::make_shared<MotorScooterCost>(config, graphreader);
}

}
}


text:
//  (C) Copyright Gennadiy Rozental 2001.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
///@file
///Defines monomorphic dataset based on forward iterable sequence
// ***************************************************************************

#ifndef BOOST_TEST_DATA_MONOMORPHIC_COLLECTION_HPP_102211GER
#define BOOST_TEST_DATA_MONOMORPHIC_COLLECTION_HPP_102211GER

// Boost.Test
#include <boost/test/data/config.hpp>
#include <boost/test/data/monomorphic/fwd.hpp>

#include <boost/test/detail/suppress_warnings.hpp>

//____________________________________________________________________________//

namespace boost {
namespace unit_test {
namespace data {
namespace monomorphic {

// ************************************************************************** //
// **************                  collection                  ************** //
// ************************************************************************** //

//!@brief Dataset from a forward iterable container (collection)
//!
//! This dataset is applicable to any container implementing a forward iterator. Note that
//! container with one element will be considered as singletons.
//! This dataset is constructible with the @ref boost::unit_test::data::make function.
template<typename C>
class collection {
    typedef typename boost::decay<C>::type col_type;
public:
    typedef typename col_type::value_type sample;

    static const int arity = 1;

    typedef typename col_type::const_iterator iterator;

    //! Constructor consumed a temporary collection or stores a reference
    explicit        collection( C&& col ) : m_col( std::forward<C>(col) ) {}

    //! Move constructor
    collection( collection&& c ) : m_col( std::forward<C>( c.m_col ) ) {}

    //! Returns the underlying collection
    C const&        col() const             { return m_col; }

    //! dataset interface
    data::size_t    size() const            { return m_col.size(); }
    iterator        begin() const           { return m_col.begin(); }

private:
    // Data members
    C               m_col;
};

//____________________________________________________________________________//

//! A collection from a forward iterable container is a dataset.
template<typename C>
struct is_dataset<collection<C>> : mpl::true_ {};

} // namespace monomorphic

//____________________________________________________________________________//

//! @overload boost::unit_test::data::make()
template<typename C>
inline typename std::enable_if<is_container_forward_iterable<C>::value,monomorphic::collection<C>>::type
make( C&& c )
{
    return monomorphic::collection<C>( std::forward<C>(c) );
}

} // namespace data
} // namespace unit_test
} // namespace boost

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_TEST_DATA_MONOMORPHIC_COLLECTION_HPP_102211GER

ext: hpp


text:
#include <Eigen/Dense>
#include <iostream>

using namespace Eigen;
using namespace std;

int main(int, char**)
{
  cout.precision(3);
  MatrixXd X = MatrixXd::Random(5,5);
MatrixXd A = X * X.transpose();
X = MatrixXd::Random(5,5);
MatrixXd B = X * X.transpose();

GeneralizedSelfAdjointEigenSolver<MatrixXd> es(A,B,EigenvaluesOnly);
cout << "The eigenvalues of the pencil (A,B) are:" << endl << es.eigenvalues() << endl;
es.compute(B,A,false);
cout << "The eigenvalues of the pencil (B,A) are:" << endl << es.eigenvalues() << endl;

  return 0;
}

max_issues_repo_name: TANHAIYU/planecalib

max_forks_repo_name: TANHAIYU/planecalib


text:
//
// Created by peri on 11/19/17.
//

#ifndef VANILLA_MODEL_HPP
#define VANILLA_MODEL_HPP

#include "../header/activation_functions.hpp"
#include "../header/init.hpp"
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/io.hpp>

class model {

    boost::numeric::ublas::matrix<long double > W_1;
    boost::numeric::ublas::matrix<long double > W_2;
    boost::numeric::ublas::matrix<long double > W_b;
    boost::numeric::ublas::matrix<long double > W_3;
    boost::numeric::ublas::matrix<long double > W_4;
    boost::numeric::ublas::matrix<long double > W_5;
    boost::numeric::ublas::matrix<long double > W_o;

    boost::numeric::ublas::matrix<long double > b_1;
    boost::numeric::ublas::matrix<long double > b_2;
    boost::numeric::ublas::matrix<long double > b_3;
    boost::numeric::ublas::matrix<long double > b_4;
    boost::numeric::ublas::matrix<long double > b_5;

    boost::numeric::ublas::matrix<long double> h1;
    boost::numeric::ublas::matrix<long double> h2;
    boost::numeric::ublas::matrix<long double> hb;
    boost::numeric::ublas::matrix<long double> h3;
    boost::numeric::ublas::matrix<long double> h4;
    boost::numeric::ublas::matrix<long double> h5;
    boost::numeric::ublas::matrix<long double> p;

    boost::numeric::ublas::matrix<long double> x;

public:
    model();

public:
    boost::numeric::ublas::matrix<long double > forward(boost::numeric::ublas::matrix<long double >& input);

public:
    void backward(boost::numeric::ublas::matrix<long double >& truth, boost::numeric::ublas::matrix<long double >& prediction);
};

#endif //VANILLA_MODEL_HPP

max_stars_repo_name: pjavia/Vanilla

max_issues_repo_name: pjavia/Vanilla

max_forks_repo_name: pjavia/Vanilla


text: #include <boost/signals/signal6.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
// ysoftman
// boost foreach 사용하기
#include <iostream>
#include <vector>
#include <string>
#include <boost/foreach.hpp>

using namespace std;

int main()
{
    cout << "boost foreach test" << endl;

    string str = "ysoftman";
    // array, vector, string, ... 등 다양하게 루프를 돌리 수 있다.
    BOOST_FOREACH(char ch, str)
    {
        cout << ch << endl;
    }

    int array[] = {1,2,3,4,5};
    BOOST_FOREACH(int n, array)
    {
        cout << n << endl;
    }

    vector<string> vec;
    vec.push_back("green");
    vec.push_back("red");
    vec.push_back("blue");
    vec.push_back("yellow");
    BOOST_FOREACH(string str, vec)
    {
        cout << str << endl;
    }

    return 0;
}


text:
#ifndef BRESENHAM_LINE_ALGORITHMS_HPP
#define BRESENHAM_LINE_ALGORITHMS_HPP

#include <boost/gil/gil_all.hpp>
#include "line-struct.hpp"

// uses the bresenham algorithm to draw a 1 pixel grayscale line on the image view img
void drawGrayscaleLine(boost::gil::gray8_view_t &img, LineData line, int opacity, bool additive);
void drawGrayscaleLineNormalAngleAdditive(boost::gil::gray8_view_t &img, LineData line, int opacity);
void drawGrayscaleLineSteepAngleAdditive(boost::gil::gray8_view_t &img, LineData line, int opacity);
void drawGrayscaleLineNormalAngleSubtractive(boost::gil::gray8_view_t &img, LineData line, int opacity);
void drawGrayscaleLineSteepAngleSubtractive(boost::gil::gray8_view_t &img, LineData line, int opacity);

// uses the bresenham algorithm to calculate a score of how much a drawn 1 pixel grayscale line would change the image
unsigned long grayscaleLineScore(boost::gil::gray8_view_t &img, LineData line, int opacity, bool additive);
unsigned long grayscaleLineScoreNormalAngleAdditive(boost::gil::gray8_view_t &img, LineData line, int opacity);
unsigned long grayscaleLineScoreSteepAngleAdditive(boost::gil::gray8_view_t &img, LineData line, int opacity);
unsigned long grayscaleLineScoreNormalAngleSubtractive(boost::gil::gray8_view_t &img, LineData line, int opacity);
unsigned long grayscaleLineScoreSteepAngleSubtractive(boost::gil::gray8_view_t &img, LineData line, int opacity);

// uses the bresenham algorithm to draw a 1 pixel rgb line on the image view img
void drawRGBLine(boost::gil::rgb8_view_t &img, LineData line, int opacity, bool additive, int channel);
void drawRGBLineNormalAngleAdditive(boost::gil::rgb8_view_t &img, LineData line, int opacity, int c);
void drawRGBLineSteepAngleAdditive(boost::gil::rgb8_view_t &img, LineData line, int opacity, int c);
void drawRGBLineNormalAngleSubtractive(boost::gil::rgb8_view_t &img, LineData line, int opacity, int c);
void drawRGBLineSteepAngleSubtractive(boost::gil::rgb8_view_t &img, LineData line, int opacity, int c);

// uses the bresenham algorithm to calculate a score of how much a drawn 1 pixel rgb line would change the image
unsigned long rgbLineScore(boost::gil::rgb8_view_t &img, LineData line, int opacity, bool additive, int channel);
unsigned long rgbLineScoreNormalAngleAdditive(boost::gil::rgb8_view_t &img, LineData line, int opacity, int c);
unsigned long rgbLineScoreSteepAngleAdditive(boost::gil::rgb8_view_t &img, LineData line, int opacity, int c);
unsigned long rgbLineScoreNormalAngleSubtractive(boost::gil::rgb8_view_t &img, LineData line, int opacity, int c);
unsigned long rgbLineScoreSteepAngleSubtractive(boost::gil::rgb8_view_t &img, LineData line, int opacity, int c);

#endif // BRESENHAM_LINE_ALGORITHMS_HPP

max_stars_repo_name: david-caroli/bildolino

max_issues_repo_name: david-caroli/bildolino

max_forks_repo_name: david-caroli/bildolino