<commit_before>// Lists APS2 boards found on network
//
// Original author: Colm Ryan
// Copyright 2016, Raytheon BBN Technologies

#include "concol.h"
#include "helpers.h"
#include "libaps2.h"

#include <iomanip>
#include <iostream>
#include <plog/Log.h>

#include <chrono>

int main(int argc, char *argv[]) {

  print_title("BBN APS2 Enumerate Utility");

  set_file_logging_level(plog::debug);
  set_console_logging_level(plog::debug);

  // First get the number of devices we can see
  unsigned numDevices = 0;
  get_numDevices(&numDevices);
  cout << concol::CYAN << numDevices << " APS device"
       << (numDevices > 1 ? "s" : "") << " found" << concol::RESET << endl;
  cout << endl;

  // If we don't see anything bail
  if (numDevices < 1)
    return 0;

  // Get IP strings and firmware versions
  const char **serialBuffer = new const char *[numDevices];
  get_device_IPs(serialBuffer);

  for (unsigned ct = 0; ct < numDevices; ct++) {
    APS2_STATUS status;
    status = connect_APS(serialBuffer[ct]);
    if (status != APS2_OK) {
      cout << concol::RED << "Failed to connect to " << serialBuffer[ct]
           << concol::RESET << endl;
      continue;
    }

    char version_string[64];
    get_firmware_version(serialBuffer[ct], nullptr, nullptr, nullptr,
                         version_string);
    double uptime{0};
    get_uptime(serialBuffer[ct], &uptime);
    std::chrono::duration<float> uptime_seconds(uptime);
    auto uptime_days = std::chrono::duration_cast<
        std::chrono::duration<int, std::ratio<24 * 3600>>>(uptime_seconds);

    std::ostringstream uptime_pretty;
    if (uptime_days.count()) {
      uptime_pretty << uptime_days.count() << " day"
                    << (uptime_days.count() > 1 ? "s " : " ");
    }
    uptime_seconds -= uptime_days;
    auto uptime_hours =
        std::chrono::duration_cast<std::chrono::hours>(uptime_seconds);
    uptime_pretty << std::setfill('0') << std::setw(2) << uptime_hours.count()
                  << ":";
    uptime_seconds -= uptime_hours;
    auto uptime_minutes =
        std::chrono::duration_cast<std::chrono::minutes>(uptime_seconds);
    uptime_pretty << std::setfill('0') << std::setw(2) << uptime_minutes.count()
                  << ":";
    uptime_seconds -= uptime_minutes;
    uptime_pretty << std::fixed << std::setprecision(3)
                  << uptime_seconds.count();

    cout << concol::CYAN << "Device " << ct + 1 << " at IPv4 address "
         << serialBuffer[ct] << " running firmware version " << version_string
         << " has been up " << uptime_pretty.str() << concol::RESET << endl;
    disconnect_APS(serialBuffer[ct]);
  }
  cout << endl;

  return 0;
}
<commit_msg>Reduce amount of info printed to console in enumerate program.<commit_after>// Lists APS2 boards found on network
//
// Original author: Colm Ryan
// Copyright 2016, Raytheon BBN Technologies

#include "concol.h"
#include "helpers.h"
#include "libaps2.h"

#include <iomanip>
#include <iostream>
#include <plog/Log.h>

#include <chrono>

int main(int argc, char *argv[]) {

  print_title("BBN APS2 Enumerate Utility");

  set_file_logging_level(plog::debug);
  set_console_logging_level(plog::info);

  // First get the number of devices we can see
  unsigned numDevices = 0;
  get_numDevices(&numDevices);
  cout << concol::CYAN << numDevices << " APS device"
       << (numDevices > 1 ? "s" : "") << " found" << concol::RESET << endl;
  cout << endl;

  // If we don't see anything bail
  if (numDevices < 1)
    return 0;

  // Get IP strings and firmware versions
  const char **serialBuffer = new const char *[numDevices];
  get_device_IPs(serialBuffer);

  for (unsigned ct = 0; ct < numDevices; ct++) {
    APS2_STATUS status;
    status = connect_APS(serialBuffer[ct]);
    if (status != APS2_OK) {
      cout << concol::RED << "Failed to connect to " << serialBuffer[ct]
           << concol::RESET << endl;
      continue;
    }

    char version_string[64];
    get_firmware_version(serialBuffer[ct], nullptr, nullptr, nullptr,
                         version_string);
    double uptime{0};
    get_uptime(serialBuffer[ct], &uptime);
    std::chrono::duration<float> uptime_seconds(uptime);
    auto uptime_days = std::chrono::duration_cast<
        std::chrono::duration<int, std::ratio<24 * 3600>>>(uptime_seconds);

    std::ostringstream uptime_pretty;
    if (uptime_days.count()) {
      uptime_pretty << uptime_days.count() << " day"
                    << (uptime_days.count() > 1 ? "s " : " ");
    }
    uptime_seconds -= uptime_days;
    auto uptime_hours =
        std::chrono::duration_cast<std::chrono::hours>(uptime_seconds);
    uptime_pretty << std::setfill('0') << std::setw(2) << uptime_hours.count()
                  << ":";
    uptime_seconds -= uptime_hours;
    auto uptime_minutes =
        std::chrono::duration_cast<std::chrono::minutes>(uptime_seconds);
    uptime_pretty << std::setfill('0') << std::setw(2) << uptime_minutes.count()
                  << ":";
    uptime_seconds -= uptime_minutes;
    uptime_pretty << std::fixed << std::setprecision(3)
                  << uptime_seconds.count();

    cout << concol::CYAN << "Device " << ct + 1 << " at IPv4 address "
         << serialBuffer[ct] << " running firmware version " << version_string
         << " has been up " << uptime_pretty.str() << concol::RESET << endl;
    disconnect_APS(serialBuffer[ct]);
  }
  cout << endl;

  return 0;
}
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2022 Project CHIP Authors
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include "BindingHandler.h"
#ifdef CONFIG_CHIP_LIB_SHELL
#include "ShellCommands.h"
#endif

#include <logging/log.h>
LOG_MODULE_DECLARE(app, CONFIG_MATTER_LOG_LEVEL);

using namespace chip;
using namespace chip::app;

void BindingHandler::Init()
{
#ifdef CONFIG_CHIP_LIB_SHELL
    SwitchCommands::RegisterSwitchCommands();
#endif
    DeviceLayer::PlatformMgr().ScheduleWork(InitInternal);
}

void BindingHandler::OnOffProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding, DeviceProxy * aDevice,
                                         void * aContext)
{
    CHIP_ERROR ret = CHIP_NO_ERROR;

    auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) {
        LOG_DBG("Binding command applied successfully!");
    };

    auto onFailure = [](CHIP_ERROR error) {
        LOG_INF("Binding command was not applied! Reason: %" CHIP_ERROR_FORMAT, error.Format());
    };

    switch (aCommandId)
    {
    case Clusters::OnOff::Commands::Toggle::Id:
        Clusters::OnOff::Commands::Toggle::Type toggleCommand;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, toggleCommand, onSuccess, onFailure);
        }
        else
        {

            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, toggleCommand);
        }
        break;

    case Clusters::OnOff::Commands::On::Id:
        Clusters::OnOff::Commands::On::Type onCommand;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, onCommand, onSuccess, onFailure);
        }
        else
        {
            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, onCommand);
        }
        break;

    case Clusters::OnOff::Commands::Off::Id:
        Clusters::OnOff::Commands::Off::Type offCommand;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, offCommand, onSuccess, onFailure);
        }
        else
        {
            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, onCommand);
        }
        break;
    default:
        LOG_DBG("Invalid binding command data - commandId is not supported");
        break;
    }
    if (CHIP_NO_ERROR != ret)
    {
        LOG_ERR("Invoke OnOff Command Request ERROR: %s", ErrorStr(ret));
    }
}

void BindingHandler::LevelControlProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding,
                                                DeviceProxy * aDevice, void * aContext)
{
    auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) {
        LOG_DBG("Binding command applied successfully!");
    };

    auto onFailure = [](CHIP_ERROR error) {
        LOG_INF("Binding command was not applied! Reason: %" CHIP_ERROR_FORMAT, error.Format());
    };

    CHIP_ERROR ret = CHIP_NO_ERROR;

    switch (aCommandId)
    {
    case Clusters::LevelControl::Commands::MoveToLevel::Id: {
        Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand;
        BindingData * data       = reinterpret_cast<BindingData *>(aContext);
        moveToLevelCommand.level = data->Value;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, moveToLevelCommand, onSuccess, onFailure);
        }
        else
        {
            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, moveToLevelCommand);
        }
    }
    break;
    default:
        LOG_DBG("Invalid binding command data - commandId is not supported");
        break;
    }
    if (CHIP_NO_ERROR != ret)
    {
        LOG_ERR("Invoke Group Command Request ERROR: %s", ErrorStr(ret));
    }
}

void BindingHandler::LightSwitchChangedHandler(const EmberBindingTableEntry & binding, DeviceProxy * deviceProxy, void * context)
{
    VerifyOrReturn(context != nullptr, LOG_ERR("Invalid context for Light switch handler"););
    BindingData * data = static_cast<BindingData *>(context);

    if (binding.type == EMBER_MULTICAST_BINDING && data->IsGroup)
    {
        switch (data->ClusterId)
        {
        case Clusters::OnOff::Id:
            OnOffProcessCommand(data->CommandId, binding, nullptr, context);
            break;
        case Clusters::LevelControl::Id:
            LevelControlProcessCommand(data->CommandId, binding, nullptr, context);
            break;
        default:
            ChipLogError(NotSpecified, "Invalid binding group command data");
            break;
        }
    }
    else if (binding.type == EMBER_UNICAST_BINDING && !data->IsGroup)
    {
        switch (data->ClusterId)
        {
        case Clusters::OnOff::Id:
            OnOffProcessCommand(data->CommandId, binding, deviceProxy, context);
            break;
        case Clusters::LevelControl::Id:
            LevelControlProcessCommand(data->CommandId, binding, deviceProxy, context);
            break;
        default:
            ChipLogError(NotSpecified, "Invalid binding unicast command data");
            break;
        }
    }
}

void BindingHandler::InitInternal(intptr_t aArg)
{
    LOG_INF("Initialize binding Handler");
    auto & server = Server::GetInstance();
    if (CHIP_NO_ERROR !=
        BindingManager::GetInstance().Init(
            { &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() }))
    {
        LOG_ERR("BindingHandler::InitInternal failed");
    }

    BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(LightSwitchChangedHandler);
    PrintBindingTable();
}

bool BindingHandler::IsGroupBound()
{
    BindingTable & bindingTable = BindingTable::GetInstance();

    for (auto & entry : bindingTable)
    {
        if (EMBER_MULTICAST_BINDING == entry.type)
        {
            return true;
        }
    }
    return false;
}

void BindingHandler::PrintBindingTable()
{
    BindingTable & bindingTable = BindingTable::GetInstance();

    LOG_INF("Binding Table size: [%d]:", bindingTable.Size());
    uint8_t i = 0;
    for (auto & entry : bindingTable)
    {
        switch (entry.type)
        {
        case EMBER_UNICAST_BINDING:
            LOG_INF("[%d] UNICAST:", i++);
            LOG_INF("\t\t+ Fabric: %d\n \
            \t+ LocalEndpoint %d \n \
            \t+ ClusterId %d \n \
            \t+ RemoteEndpointId %d \n \
            \t+ NodeId %d",
                    (int) entry.fabricIndex, (int) entry.local, (int) entry.clusterId.Value(), (int) entry.remote,
                    (int) entry.nodeId);
            break;
        case EMBER_MULTICAST_BINDING:
            LOG_INF("[%d] GROUP:", i++);
            LOG_INF("\t\t+ Fabric: %d\n \
            \t+ LocalEndpoint %d \n \
            \t+ RemoteEndpointId %d \n \
            \t+ GroupId %d",
                    (int) entry.fabricIndex, (int) entry.local, (int) entry.remote, (int) entry.groupId);
            break;
        case EMBER_UNUSED_BINDING:
            LOG_INF("[%d] UNUSED", i++);
            break;
        case EMBER_MANY_TO_ONE_BINDING:
            LOG_INF("[%d] MANY TO ONE", i++);
            break;
        default:
            break;
        }
    }
}

void BindingHandler::SwitchWorkerHandler(intptr_t aContext)
{
    VerifyOrReturn(aContext != 0, LOG_ERR("Invalid Swich data"));

    BindingData * data = reinterpret_cast<BindingData *>(aContext);
    LOG_INF("Notify Bounded Cluster | endpoint: %d cluster: %d", data->EndpointId, data->ClusterId);
    BindingManager::GetInstance().NotifyBoundClusterChanged(data->EndpointId, data->ClusterId, static_cast<void *>(data));

    Platform::Delete(data);
}
<commit_msg>[nrfconnect] Fixed sending light switch off command (#17110)<commit_after>/*
 *
 *    Copyright (c) 2022 Project CHIP Authors
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#include "BindingHandler.h"
#ifdef CONFIG_CHIP_LIB_SHELL
#include "ShellCommands.h"
#endif

#include <logging/log.h>
LOG_MODULE_DECLARE(app, CONFIG_MATTER_LOG_LEVEL);

using namespace chip;
using namespace chip::app;

void BindingHandler::Init()
{
#ifdef CONFIG_CHIP_LIB_SHELL
    SwitchCommands::RegisterSwitchCommands();
#endif
    DeviceLayer::PlatformMgr().ScheduleWork(InitInternal);
}

void BindingHandler::OnOffProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding, DeviceProxy * aDevice,
                                         void * aContext)
{
    CHIP_ERROR ret = CHIP_NO_ERROR;

    auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) {
        LOG_DBG("Binding command applied successfully!");
    };

    auto onFailure = [](CHIP_ERROR error) {
        LOG_INF("Binding command was not applied! Reason: %" CHIP_ERROR_FORMAT, error.Format());
    };

    switch (aCommandId)
    {
    case Clusters::OnOff::Commands::Toggle::Id:
        Clusters::OnOff::Commands::Toggle::Type toggleCommand;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, toggleCommand, onSuccess, onFailure);
        }
        else
        {

            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, toggleCommand);
        }
        break;

    case Clusters::OnOff::Commands::On::Id:
        Clusters::OnOff::Commands::On::Type onCommand;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, onCommand, onSuccess, onFailure);
        }
        else
        {
            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, onCommand);
        }
        break;

    case Clusters::OnOff::Commands::Off::Id:
        Clusters::OnOff::Commands::Off::Type offCommand;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, offCommand, onSuccess, onFailure);
        }
        else
        {
            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, offCommand);
        }
        break;
    default:
        LOG_DBG("Invalid binding command data - commandId is not supported");
        break;
    }
    if (CHIP_NO_ERROR != ret)
    {
        LOG_ERR("Invoke OnOff Command Request ERROR: %s", ErrorStr(ret));
    }
}

void BindingHandler::LevelControlProcessCommand(CommandId aCommandId, const EmberBindingTableEntry & aBinding,
                                                DeviceProxy * aDevice, void * aContext)
{
    auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) {
        LOG_DBG("Binding command applied successfully!");
    };

    auto onFailure = [](CHIP_ERROR error) {
        LOG_INF("Binding command was not applied! Reason: %" CHIP_ERROR_FORMAT, error.Format());
    };

    CHIP_ERROR ret = CHIP_NO_ERROR;

    switch (aCommandId)
    {
    case Clusters::LevelControl::Commands::MoveToLevel::Id: {
        Clusters::LevelControl::Commands::MoveToLevel::Type moveToLevelCommand;
        BindingData * data       = reinterpret_cast<BindingData *>(aContext);
        moveToLevelCommand.level = data->Value;
        if (aDevice)
        {
            ret = Controller::InvokeCommandRequest(aDevice->GetExchangeManager(), aDevice->GetSecureSession().Value(),
                                                   aBinding.remote, moveToLevelCommand, onSuccess, onFailure);
        }
        else
        {
            Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
            ret = Controller::InvokeGroupCommandRequest(&exchangeMgr, aBinding.fabricIndex, aBinding.groupId, moveToLevelCommand);
        }
    }
    break;
    default:
        LOG_DBG("Invalid binding command data - commandId is not supported");
        break;
    }
    if (CHIP_NO_ERROR != ret)
    {
        LOG_ERR("Invoke Group Command Request ERROR: %s", ErrorStr(ret));
    }
}

void BindingHandler::LightSwitchChangedHandler(const EmberBindingTableEntry & binding, DeviceProxy * deviceProxy, void * context)
{
    VerifyOrReturn(context != nullptr, LOG_ERR("Invalid context for Light switch handler"););
    BindingData * data = static_cast<BindingData *>(context);

    if (binding.type == EMBER_MULTICAST_BINDING && data->IsGroup)
    {
        switch (data->ClusterId)
        {
        case Clusters::OnOff::Id:
            OnOffProcessCommand(data->CommandId, binding, nullptr, context);
            break;
        case Clusters::LevelControl::Id:
            LevelControlProcessCommand(data->CommandId, binding, nullptr, context);
            break;
        default:
            ChipLogError(NotSpecified, "Invalid binding group command data");
            break;
        }
    }
    else if (binding.type == EMBER_UNICAST_BINDING && !data->IsGroup)
    {
        switch (data->ClusterId)
        {
        case Clusters::OnOff::Id:
            OnOffProcessCommand(data->CommandId, binding, deviceProxy, context);
            break;
        case Clusters::LevelControl::Id:
            LevelControlProcessCommand(data->CommandId, binding, deviceProxy, context);
            break;
        default:
            ChipLogError(NotSpecified, "Invalid binding unicast command data");
            break;
        }
    }
}

void BindingHandler::InitInternal(intptr_t aArg)
{
    LOG_INF("Initialize binding Handler");
    auto & server = Server::GetInstance();
    if (CHIP_NO_ERROR !=
        BindingManager::GetInstance().Init(
            { &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() }))
    {
        LOG_ERR("BindingHandler::InitInternal failed");
    }

    BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(LightSwitchChangedHandler);
    PrintBindingTable();
}

bool BindingHandler::IsGroupBound()
{
    BindingTable & bindingTable = BindingTable::GetInstance();

    for (auto & entry : bindingTable)
    {
        if (EMBER_MULTICAST_BINDING == entry.type)
        {
            return true;
        }
    }
    return false;
}

void BindingHandler::PrintBindingTable()
{
    BindingTable & bindingTable = BindingTable::GetInstance();

    LOG_INF("Binding Table size: [%d]:", bindingTable.Size());
    uint8_t i = 0;
    for (auto & entry : bindingTable)
    {
        switch (entry.type)
        {
        case EMBER_UNICAST_BINDING:
            LOG_INF("[%d] UNICAST:", i++);
            LOG_INF("\t\t+ Fabric: %d\n \
            \t+ LocalEndpoint %d \n \
            \t+ ClusterId %d \n \
            \t+ RemoteEndpointId %d \n \
            \t+ NodeId %d",
                    (int) entry.fabricIndex, (int) entry.local, (int) entry.clusterId.Value(), (int) entry.remote,
                    (int) entry.nodeId);
            break;
        case EMBER_MULTICAST_BINDING:
            LOG_INF("[%d] GROUP:", i++);
            LOG_INF("\t\t+ Fabric: %d\n \
            \t+ LocalEndpoint %d \n \
            \t+ RemoteEndpointId %d \n \
            \t+ GroupId %d",
                    (int) entry.fabricIndex, (int) entry.local, (int) entry.remote, (int) entry.groupId);
            break;
        case EMBER_UNUSED_BINDING:
            LOG_INF("[%d] UNUSED", i++);
            break;
        case EMBER_MANY_TO_ONE_BINDING:
            LOG_INF("[%d] MANY TO ONE", i++);
            break;
        default:
            break;
        }
    }
}

void BindingHandler::SwitchWorkerHandler(intptr_t aContext)
{
    VerifyOrReturn(aContext != 0, LOG_ERR("Invalid Swich data"));

    BindingData * data = reinterpret_cast<BindingData *>(aContext);
    LOG_INF("Notify Bounded Cluster | endpoint: %d cluster: %d", data->EndpointId, data->ClusterId);
    BindingManager::GetInstance().NotifyBoundClusterChanged(data->EndpointId, data->ClusterId, static_cast<void *>(data));

    Platform::Delete(data);
}
<|endoftext|>


<commit_before>namespace plb{

  inline PlbCaseTimer::PlbCaseTimer()
  {
    index_t global("global",GLOBAL_IND);
    indexMap.insert(global);

    clockVec.push_back(clock());
    timeVec.push_back(0);
    activeVec.push_back(false);
  }

  inline void PlbCaseTimer::registerCustom(char const *name_)
  {
    std::string name(name_);

    index_map_t::const_iterator it = indexMap.find(name);

    if(it != indexMap.end()){
      std::string errmsg("Error: custom timer ");
      errmsg.append(name);
      errmsg.append(" registered twice\n");
      throw PlbCaseTimerException(errmsg.c_str());
    }

    int index = clockVec.size();
    index_t ins(name,index);
    indexMap.insert(ins);

    clockVec.push_back(clock());
    timeVec.push_back(0.);
    activeVec.push_back(false);
  }

  inline void PlbCaseTimer::startGlobal()
  {
    if(!global::mpi().isMainProcessor()) return;
    start(GLOBAL_IND);
  }

  inline void PlbCaseTimer::stopGlobal()
  {
    if(!global::mpi().isMainProcessor()) return;
    stop(GLOBAL_IND);
  }

  inline void PlbCaseTimer::startCustom(char const *name_)
  {
    if(!global::mpi().isMainProcessor()) return;
    int index = getIndex(name_);
    start(index);
  }

  inline void PlbCaseTimer::stopCustom(char const *name_)
  {
    if(!global::mpi().isMainProcessor()) return;
    int index = getIndex(name_);
    stop(index);
  }

  // get index for custom name

  inline int PlbCaseTimer::getIndex(char const *name_)
  {
    std::string name(name_);

    index_map_t::const_iterator it = indexMap.find(name);

    if(it == indexMap.end()){
      std::string errmsg("Error: custom timer ");
      errmsg.append(name);
      errmsg.append(" not found\n");
      throw PlbCaseTimerException(errmsg.c_str());
    }

    return it->second;
  }

  // generic start/stop functions that actually handle
  // the bookkeeping with clock_t

  inline void PlbCaseTimer::start(int const index)
  {
    if(activeVec[index]){
      std::string errmsg("Error: custom timer started twice");
      throw PlbCaseTimerException(errmsg.c_str());
    }

    clockVec[index] = clock();
    activeVec[index] = true;
  }

  inline void PlbCaseTimer::stop(int const index)
  {
    if(!activeVec[index]){
      std::string errmsg("Error: custom timer that should be stopped was not started before");
      throw PlbCaseTimerException(errmsg.c_str());
    }

    clock_t now = clock();

    timeVec[index] += now - clockVec[index];
    activeVec[index] = false;
  }

  inline double PlbCaseTimer::computeOther()
  {
    clock_t sum(0);
    for(pluint i=1;i<timeVec.size();i++)
      sum += timeVec[i];

    clock_t other = timeVec[0] - sum;
    return other/CPS;
  }

  inline void PlbCaseTimer::writeLog(Parallel_ostream &out)
  {
    for(index_map_t::iterator it = indexMap.begin();it!=indexMap.end();++it){
      out << "Timer " << it->first << " : "
          << timeVec[it->second]/CPS << " seconds, "
          << (double)timeVec[it->second]/(double)timeVec[GLOBAL_IND]*100 << "%" << std::endl;
    }

    double other = computeOther();
    out << "Timer other : " << other << " seconds, "
        << other/(timeVec[GLOBAL_IND]/CPS) << "%" << std::endl;

  }

  inline void PlbCaseTimer::writeLogJSON(std::string fname)
  {
    fname.insert(0,global::directories().getOutputDir());

    plb_ofstream out(fname.c_str());

    out << "{\n";
    out << "  \"timer\" : [\n";

    index_map_t::iterator it = indexMap.begin();
    for(index_map_t::iterator it = indexMap.begin();it!=indexMap.end();++it){
      out << "    {";
      out << " \"name\" : \"" << it->first << "\","
          << " \"time\" : " << timeVec[it->second]/CPS
          << " \"fraction\" : " << (double)timeVec[it->second]/(double)timeVec[GLOBAL_IND];
      out << " },\n";
    }

    out << "    {";
    out << " \"name\" : \"other\",";
    out << " \"time\" : " << computeOther() << ",";
    out << " \"fraction\" : " << computeOther()/(timeVec[GLOBAL_IND]/CPS);
    out << " }\n";

    out << "  ]\n";
    out << "}\n";

    out.close();
  }
}; // namespace plb
<commit_msg>fixed small error in writeLogJSON<commit_after>namespace plb{

  inline PlbCaseTimer::PlbCaseTimer()
  {
    index_t global("global",GLOBAL_IND);
    indexMap.insert(global);

    clockVec.push_back(clock());
    timeVec.push_back(0);
    activeVec.push_back(false);
  }

  inline void PlbCaseTimer::registerCustom(char const *name_)
  {
    std::string name(name_);

    index_map_t::const_iterator it = indexMap.find(name);

    if(it != indexMap.end()){
      std::string errmsg("Error: custom timer ");
      errmsg.append(name);
      errmsg.append(" registered twice\n");
      throw PlbCaseTimerException(errmsg.c_str());
    }

    int index = clockVec.size();
    index_t ins(name,index);
    indexMap.insert(ins);

    clockVec.push_back(clock());
    timeVec.push_back(0.);
    activeVec.push_back(false);
  }

  inline void PlbCaseTimer::startGlobal()
  {
    if(!global::mpi().isMainProcessor()) return;
    start(GLOBAL_IND);
  }

  inline void PlbCaseTimer::stopGlobal()
  {
    if(!global::mpi().isMainProcessor()) return;
    stop(GLOBAL_IND);
  }

  inline void PlbCaseTimer::startCustom(char const *name_)
  {
    if(!global::mpi().isMainProcessor()) return;
    int index = getIndex(name_);
    start(index);
  }

  inline void PlbCaseTimer::stopCustom(char const *name_)
  {
    if(!global::mpi().isMainProcessor()) return;
    int index = getIndex(name_);
    stop(index);
  }

  // get index for custom name

  inline int PlbCaseTimer::getIndex(char const *name_)
  {
    std::string name(name_);

    index_map_t::const_iterator it = indexMap.find(name);

    if(it == indexMap.end()){
      std::string errmsg("Error: custom timer ");
      errmsg.append(name);
      errmsg.append(" not found\n");
      throw PlbCaseTimerException(errmsg.c_str());
    }

    return it->second;
  }

  // generic start/stop functions that actually handle
  // the bookkeeping with clock_t

  inline void PlbCaseTimer::start(int const index)
  {
    if(activeVec[index]){
      std::string errmsg("Error: custom timer started twice");
      throw PlbCaseTimerException(errmsg.c_str());
    }

    clockVec[index] = clock();
    activeVec[index] = true;
  }

  inline void PlbCaseTimer::stop(int const index)
  {
    if(!activeVec[index]){
      std::string errmsg("Error: custom timer that should be stopped was not started before");
      throw PlbCaseTimerException(errmsg.c_str());
    }

    clock_t now = clock();

    timeVec[index] += now - clockVec[index];
    activeVec[index] = false;
  }

  inline double PlbCaseTimer::computeOther()
  {
    clock_t sum(0);
    for(pluint i=1;i<timeVec.size();i++)
      sum += timeVec[i];

    clock_t other = timeVec[0] - sum;
    return other/CPS;
  }

  inline void PlbCaseTimer::writeLog(Parallel_ostream &out)
  {
    for(index_map_t::iterator it = indexMap.begin();it!=indexMap.end();++it){
      out << "Timer " << it->first << " : "
          << timeVec[it->second]/CPS << " seconds, "
          << (double)timeVec[it->second]/(double)timeVec[GLOBAL_IND]*100 << "%" << std::endl;
    }

    double other = computeOther();
    out << "Timer other : " << other << " seconds, "
        << other/(timeVec[GLOBAL_IND]/CPS) << "%" << std::endl;

  }

  inline void PlbCaseTimer::writeLogJSON(std::string fname)
  {
    fname.insert(0,global::directories().getOutputDir());

    plb_ofstream out(fname.c_str());

    out << "{\n";
    out << "   \"timer\":[\n";

    index_map_t::iterator it = indexMap.begin();
    for(index_map_t::iterator it = indexMap.begin();it!=indexMap.end();++it){
      out << "      {";
      out << "         \"name\":\"" << it->first << "\",\n";
      out << "         \"time\":" << timeVec[it->second]/CPS << ",\n";
      out << "         \"fraction\":" << (double)timeVec[it->second]/(double)timeVec[GLOBAL_IND] << "\n";
      out << "      },\n";
    }

    out << "      {";
    out << "         \"name\":\"other\",\n";
    out << "         \"time\" : " << computeOther() << ",\n";
    out << "         \"fraction\" : " << computeOther()/(timeVec[GLOBAL_IND]/CPS << "\n";
    out << "      }\n";

    out << "   ]\n";
    out << "}\n";

    out.close();
  }
}; // namespace plb
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord-base/SHA1.h>
#include <fnord-base/stringutil.h>

namespace fnord {

SHA1Hash::SHA1Hash() {
  memset(hash, 0,sizeof(hash));
}

SHA1Hash::SHA1Hash(DeferInitialization) {
  /* initialize nothing, this ctor is private and can only be called by SHA1 */
}

SHA1Hash::SHA1Hash(const void* data, size_t size) {
  if (size != sizeof(hash)) {
    RAISE(kRuntimeError, "invalid SHA1Hash");
  }

  memcpy(&hash, data, sizeof(hash));
}

String SHA1Hash::toString() const {
  return StringUtil::hexPrint(hash, sizeof(hash), false);
}

SHA1Hash SHA1::compute(const Buffer& data) {
  SHA1Hash hash(SHA1Hash::DeferInitialization{});
  compute(data.data(), data.size(), &hash);
  return hash;
}

void SHA1::compute(const Buffer& data, SHA1Hash* out) {
  compute(data.data(), data.size(), out);
}

SHA1Hash SHA1::compute(const String& data) {
  SHA1Hash hash(SHA1Hash::DeferInitialization{});
  compute(data.data(), data.size(), &hash);
  return hash;
}

void SHA1::compute(const String& data, SHA1Hash* out) {
  compute(data.data(), data.size(), out);
}

SHA1Hash SHA1::compute(const void* data, size_t size) {
  SHA1Hash hash(SHA1Hash::DeferInitialization{});
  compute(data, size, &hash);
  return hash;
}

/**
 * SHA1 Implementation from
 *    https://code.google.com/p/smallsha1/source/browse/trunk/sha1.h
 *
 * Copyright (c) 2011, Micael Hildenborg
 * 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 Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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.
 */
static inline const unsigned int rol(
    const unsigned int value,
    const unsigned int steps) {
  return ((value << steps) | (value >> (32 - steps)));
}

// Sets the first 16 integers in the buffert to zero.
// Used for clearing the W buffert.
static inline void clearWBuffert(unsigned int* buffert) {
  for (int pos = 16; --pos >= 0;) {
    buffert[pos] = 0;
  }
}

static void innerHash(unsigned int* result, unsigned int* w) {
  unsigned int a = result[0];
  unsigned int b = result[1];
  unsigned int c = result[2];
  unsigned int d = result[3];
  unsigned int e = result[4];

  int round = 0;

  #define sha1macro(func,val) \
              { \
      const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
                      e = d; \
                      d = c; \
                      c = rol(b, 30); \
                      b = a; \
                      a = t; \
              }

  while (round < 16) {
      sha1macro((b & c) | (~b & d), 0x5a827999)
      ++round;
  }
  while (round < 20) {
      w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
      sha1macro((b & c) | (~b & d), 0x5a827999)
      ++round;
  }
  while (round < 40) {
      w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
      sha1macro(b ^ c ^ d, 0x6ed9eba1)
      ++round;
  }
  while (round < 60) {
      w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
      sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
      ++round;
  }
  while (round < 80) {
      w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
      sha1macro(b ^ c ^ d, 0xca62c1d6)
      ++round;
  }

  #undef sha1macro

  result[0] += a;
  result[1] += b;
  result[2] += c;
  result[3] += d;
  result[4] += e;
}

void SHA1::compute(const void* data, size_t size, SHA1Hash* out) {
  // Init the result array.
  unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };

  // Cast the void src pointer to be the byte array we can work with.
  const unsigned char* sarray = (const unsigned char*) data;

  // The reusable round buffer
  unsigned int w[80];

  // Loop through all complete 64byte blocks.
  const int endOfFullBlocks = size - 64;
  int endCurrentBlock;
  int currentBlock = 0;

  while (currentBlock <= endOfFullBlocks) {
    endCurrentBlock = currentBlock + 64;

    // Init the round buffer with the 64 byte block data.
    for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) {
      // This line will swap endian on big endian and keep endian on little endian.
      w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
              | (((unsigned int) sarray[currentBlock + 2]) << 8)
              | (((unsigned int) sarray[currentBlock + 1]) << 16)
              | (((unsigned int) sarray[currentBlock]) << 24);
    }

    innerHash(result, w);
  }

  // Handle the last and not full 64 byte block if existing.
  endCurrentBlock = size - currentBlock;
  clearWBuffert(w);
  int lastBlockBytes = 0;
  for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) {
    w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
  }

  w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
  if (endCurrentBlock >= 56) {
      innerHash(result, w);
      clearWBuffert(w);
  }
  w[15] = size << 3;
  innerHash(result, w);

  // Store hash in result pointer, and make sure we get in in the correct order on both endian models.
  for (int hashByte = 20; --hashByte >= 0;) {
      out->hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
  }
}

}
<commit_msg>impl SHA1Hash::operator{==,<,>}<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <string.h>
#include <fnord-base/SHA1.h>
#include <fnord-base/stringutil.h>

namespace fnord {

SHA1Hash::SHA1Hash() {
  memset(hash, 0, sizeof(hash));
}

SHA1Hash::SHA1Hash(DeferInitialization) {
  /* initialize nothing, this ctor is private and can only be called by SHA1 */
}

bool SHA1Hash::operator==(const SHA1Hash& other) const {
  return strncmp((char*) hash, (char*) other.hash, sizeof(hash)) == 0;
}

bool SHA1Hash::operator<(const SHA1Hash& other) const {
  return strncmp((char*) hash, (char*) other.hash, sizeof(hash)) < 0;
}

bool SHA1Hash::operator>(const SHA1Hash& other) const {
  return strncmp((char*) hash, (char*) other.hash, sizeof(hash)) > 0;
}

SHA1Hash::SHA1Hash(const void* data, size_t size) {
  if (size != sizeof(hash)) {
    RAISE(kRuntimeError, "invalid SHA1Hash");
  }

  memcpy(&hash, data, sizeof(hash));
}

String SHA1Hash::toString() const {
  return StringUtil::hexPrint(hash, sizeof(hash), false);
}

SHA1Hash SHA1::compute(const Buffer& data) {
  SHA1Hash hash(SHA1Hash::DeferInitialization{});
  compute(data.data(), data.size(), &hash);
  return hash;
}

void SHA1::compute(const Buffer& data, SHA1Hash* out) {
  compute(data.data(), data.size(), out);
}

SHA1Hash SHA1::compute(const String& data) {
  SHA1Hash hash(SHA1Hash::DeferInitialization{});
  compute(data.data(), data.size(), &hash);
  return hash;
}

void SHA1::compute(const String& data, SHA1Hash* out) {
  compute(data.data(), data.size(), out);
}

SHA1Hash SHA1::compute(const void* data, size_t size) {
  SHA1Hash hash(SHA1Hash::DeferInitialization{});
  compute(data, size, &hash);
  return hash;
}

/**
 * SHA1 Implementation from
 *    https://code.google.com/p/smallsha1/source/browse/trunk/sha1.h
 *
 * Copyright (c) 2011, Micael Hildenborg
 * 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 Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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.
 */
static inline const unsigned int rol(
    const unsigned int value,
    const unsigned int steps) {
  return ((value << steps) | (value >> (32 - steps)));
}

// Sets the first 16 integers in the buffert to zero.
// Used for clearing the W buffert.
static inline void clearWBuffert(unsigned int* buffert) {
  for (int pos = 16; --pos >= 0;) {
    buffert[pos] = 0;
  }
}

static void innerHash(unsigned int* result, unsigned int* w) {
  unsigned int a = result[0];
  unsigned int b = result[1];
  unsigned int c = result[2];
  unsigned int d = result[3];
  unsigned int e = result[4];

  int round = 0;

  #define sha1macro(func,val) \
              { \
      const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
                      e = d; \
                      d = c; \
                      c = rol(b, 30); \
                      b = a; \
                      a = t; \
              }

  while (round < 16) {
      sha1macro((b & c) | (~b & d), 0x5a827999)
      ++round;
  }
  while (round < 20) {
      w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
      sha1macro((b & c) | (~b & d), 0x5a827999)
      ++round;
  }
  while (round < 40) {
      w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
      sha1macro(b ^ c ^ d, 0x6ed9eba1)
      ++round;
  }
  while (round < 60) {
      w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
      sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
      ++round;
  }
  while (round < 80) {
      w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
      sha1macro(b ^ c ^ d, 0xca62c1d6)
      ++round;
  }

  #undef sha1macro

  result[0] += a;
  result[1] += b;
  result[2] += c;
  result[3] += d;
  result[4] += e;
}

void SHA1::compute(const void* data, size_t size, SHA1Hash* out) {
  // Init the result array.
  unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };

  // Cast the void src pointer to be the byte array we can work with.
  const unsigned char* sarray = (const unsigned char*) data;

  // The reusable round buffer
  unsigned int w[80];

  // Loop through all complete 64byte blocks.
  const int endOfFullBlocks = size - 64;
  int endCurrentBlock;
  int currentBlock = 0;

  while (currentBlock <= endOfFullBlocks) {
    endCurrentBlock = currentBlock + 64;

    // Init the round buffer with the 64 byte block data.
    for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) {
      // This line will swap endian on big endian and keep endian on little endian.
      w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
              | (((unsigned int) sarray[currentBlock + 2]) << 8)
              | (((unsigned int) sarray[currentBlock + 1]) << 16)
              | (((unsigned int) sarray[currentBlock]) << 24);
    }

    innerHash(result, w);
  }

  // Handle the last and not full 64 byte block if existing.
  endCurrentBlock = size - currentBlock;
  clearWBuffert(w);
  int lastBlockBytes = 0;
  for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) {
    w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
  }

  w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
  if (endCurrentBlock >= 56) {
      innerHash(result, w);
      clearWBuffert(w);
  }
  w[15] = size << 3;
  innerHash(result, w);

  // Store hash in result pointer, and make sure we get in in the correct order on both endian models.
  for (int hashByte = 20; --hashByte >= 0;) {
      out->hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
  }
}

}
<|endoftext|>


<commit_before>#ifndef CLUSTERING_ADMINISTRATION_PARSER_MAKER_TCC_
#define CLUSTERING_ADMINISTRATION_PARSER_MAKER_TCC_

#include "clustering/administration/parser_maker.hpp"

#include <string>

template<class protocol_t, class parser_t>
parser_maker_t<protocol_t, parser_t>::parser_maker_t(mailbox_manager_t *_mailbox_manager,
                               boost::shared_ptr<semilattice_read_view_t<cow_ptr_t<namespaces_semilattice_metadata_t<protocol_t> > > > _namespaces_semilattice_metadata,
                               int _port_offset,
                               namespace_repo_t<protocol_t> *_repo,
                               local_issue_tracker_t *_local_issue_tracker,
                               perfmon_collection_repo_t *_perfmon_collection_repo)
    : mailbox_manager(_mailbox_manager),
      namespaces_semilattice_metadata(_namespaces_semilattice_metadata),
      port_offset(_port_offset),
      repo(_repo),
      namespaces_subscription(boost::bind(&parser_maker_t::on_change, this), namespaces_semilattice_metadata),
      perfmon_collection_repo(_perfmon_collection_repo),
      local_issue_tracker(_local_issue_tracker)
{
    on_change();
}

template<class protocol_t>
int get_port(const namespace_semilattice_metadata_t<protocol_t> &ns, int port_offset) {
    if (ns.port.get() == 0)
        return 0;

    return ns.port.get() + port_offset;
}

// TODO(1253): Jesus fucking christ what the fuck is this shit.
static const char * ns_name_in_conflict = "<in conflict>";

template<class protocol_t, class parser_t>
void parser_maker_t<protocol_t, parser_t>::on_change() {
    ASSERT_NO_CORO_WAITING;

    cow_ptr_t<namespaces_semilattice_metadata_t<protocol_t> > snapshot = namespaces_semilattice_metadata->get();

    for (typename namespaces_semilattice_metadata_t<protocol_t>::namespace_map_t::const_iterator it  = snapshot->namespaces.begin();
                                                                                it != snapshot->namespaces.end();
                                                                                ++it) {
        typename boost::ptr_map<namespace_id_t, ns_record_t>::iterator handled_ns = namespaces_being_handled.find(it->first);

        /* Destroy parsers as necessary, by pulsing the `stopper` cond on the
        `ns_record_t` so that the `serve_queries()` coroutine will stop */
        if (handled_ns != namespaces_being_handled.end() && (
                          it->second.is_deleted() ||
                          it->second.get().port.in_conflict() ||
                          handled_ns->second->port != get_port(it->second.get(), port_offset)
                          )) {

            if (!handled_ns->second->stopper.is_pulsed()) {
                handled_ns->second->stopper.pulse();
            }
        }

        /* Create parsers as necessary by spawning instances of
        `serve_queries()` */
        if (handled_ns == namespaces_being_handled.end() && !it->second.is_deleted() && !it->second.get().port.in_conflict()) {
            vclock_t<name_string_t> v_ns_name = it->second.get().name;
            std::string ns_name(v_ns_name.in_conflict() ? ns_name_in_conflict : v_ns_name.get().str() /* TODO(1253) */);

            int port = get_port(it->second.get(), port_offset);
            namespace_id_t tmp = it->first;
            namespaces_being_handled.insert(tmp, new ns_record_t(port));
            coro_t::spawn_sometime(boost::bind(
                &parser_maker_t::serve_queries, this,
                ns_name, it->first, port, auto_drainer_t::lock_t(&drainer)));
        }
    }
}

template<class protocol_t, class parser_t>
void parser_maker_t<protocol_t, parser_t>::serve_queries(std::string ns_name, namespace_id_t ns, int port, auto_drainer_t::lock_t keepalive) {
    try {
        logINF("Listening for queries for the namespace '%s' %s on port %d.\n", ns_name.c_str(), uuid_to_str(ns).c_str(), port);

        wait_any_t interruptor(&namespaces_being_handled.find(ns)->second->stopper, keepalive.get_drain_signal());
        parser_t parser(port, repo, ns, &perfmon_collection_repo->get_perfmon_collections_for_namespace(ns)->namespace_collection);

        signal_t *is_bound = parser.get_bound_signal();

        scoped_ptr_t<local_issue_tracker_t::entry_t> bound_issue_tracker_entry;
        issue_subscription_t bound_subscription(&bound_issue_tracker_entry);
        local_issue_t bound_issue("PORT_CONFLICT", true, strprintf("cannot bind to port %d to serve namespace %s", port, ns_name.c_str()));

        // Don't bother propogating the issue unless we don't immediately connect
        if (!is_bound->is_pulsed()) {

            // Propogates the issue through the cluster
            bound_issue_tracker_entry.init(
                    new local_issue_tracker_t::entry_t(local_issue_tracker, bound_issue));

            // Clears the issue from the cluster when 'is_bound' is pulsed
            bound_subscription.reset(is_bound);
        }

        // Because we block here, the local issue related variables will live
        // for the lifetime of the server.
        interruptor.wait_lazily_unordered();

        logINF("Stopped listening for queries for the namespace '%s' %s on port %d.\n", ns_name.c_str(), uuid_to_str(ns).c_str(), port);
    } catch (interrupted_exc_t) {
        /* pass */
    }

    namespaces_being_handled.erase(ns);

    if (!keepalive.get_drain_signal()->is_pulsed()) {
        /* If we were stopped due to a port change, make sure that a new
        instance of `serve_queries()` gets started with the correct port */
        on_change();
    }
}

#endif /* CLUSTERING_ADMINISTRATION_PARSER_MAKER_TCC_ */
<commit_msg>Removed "Jesus fucking christ what the fuck is this shit" comment.<commit_after>#ifndef CLUSTERING_ADMINISTRATION_PARSER_MAKER_TCC_
#define CLUSTERING_ADMINISTRATION_PARSER_MAKER_TCC_

#include "clustering/administration/parser_maker.hpp"

#include <string>

template<class protocol_t, class parser_t>
parser_maker_t<protocol_t, parser_t>::parser_maker_t(mailbox_manager_t *_mailbox_manager,
                               boost::shared_ptr<semilattice_read_view_t<cow_ptr_t<namespaces_semilattice_metadata_t<protocol_t> > > > _namespaces_semilattice_metadata,
                               int _port_offset,
                               namespace_repo_t<protocol_t> *_repo,
                               local_issue_tracker_t *_local_issue_tracker,
                               perfmon_collection_repo_t *_perfmon_collection_repo)
    : mailbox_manager(_mailbox_manager),
      namespaces_semilattice_metadata(_namespaces_semilattice_metadata),
      port_offset(_port_offset),
      repo(_repo),
      namespaces_subscription(boost::bind(&parser_maker_t::on_change, this), namespaces_semilattice_metadata),
      perfmon_collection_repo(_perfmon_collection_repo),
      local_issue_tracker(_local_issue_tracker)
{
    on_change();
}

template<class protocol_t>
int get_port(const namespace_semilattice_metadata_t<protocol_t> &ns, int port_offset) {
    if (ns.port.get() == 0)
        return 0;

    return ns.port.get() + port_offset;
}

static const char * ns_name_in_conflict = "<in conflict>";

template<class protocol_t, class parser_t>
void parser_maker_t<protocol_t, parser_t>::on_change() {
    ASSERT_NO_CORO_WAITING;

    cow_ptr_t<namespaces_semilattice_metadata_t<protocol_t> > snapshot = namespaces_semilattice_metadata->get();

    for (typename namespaces_semilattice_metadata_t<protocol_t>::namespace_map_t::const_iterator it  = snapshot->namespaces.begin();
                                                                                it != snapshot->namespaces.end();
                                                                                ++it) {
        typename boost::ptr_map<namespace_id_t, ns_record_t>::iterator handled_ns = namespaces_being_handled.find(it->first);

        /* Destroy parsers as necessary, by pulsing the `stopper` cond on the
        `ns_record_t` so that the `serve_queries()` coroutine will stop */
        if (handled_ns != namespaces_being_handled.end() && (
                          it->second.is_deleted() ||
                          it->second.get().port.in_conflict() ||
                          handled_ns->second->port != get_port(it->second.get(), port_offset)
                          )) {

            if (!handled_ns->second->stopper.is_pulsed()) {
                handled_ns->second->stopper.pulse();
            }
        }

        /* Create parsers as necessary by spawning instances of
        `serve_queries()` */
        if (handled_ns == namespaces_being_handled.end() && !it->second.is_deleted() && !it->second.get().port.in_conflict()) {
            vclock_t<name_string_t> v_ns_name = it->second.get().name;
            std::string ns_name(v_ns_name.in_conflict() ? ns_name_in_conflict : v_ns_name.get().str() /* TODO(1253) */);

            int port = get_port(it->second.get(), port_offset);
            namespace_id_t tmp = it->first;
            namespaces_being_handled.insert(tmp, new ns_record_t(port));
            coro_t::spawn_sometime(boost::bind(
                &parser_maker_t::serve_queries, this,
                ns_name, it->first, port, auto_drainer_t::lock_t(&drainer)));
        }
    }
}

template<class protocol_t, class parser_t>
void parser_maker_t<protocol_t, parser_t>::serve_queries(std::string ns_name, namespace_id_t ns, int port, auto_drainer_t::lock_t keepalive) {
    try {
        logINF("Listening for queries for the namespace '%s' %s on port %d.\n", ns_name.c_str(), uuid_to_str(ns).c_str(), port);

        wait_any_t interruptor(&namespaces_being_handled.find(ns)->second->stopper, keepalive.get_drain_signal());
        parser_t parser(port, repo, ns, &perfmon_collection_repo->get_perfmon_collections_for_namespace(ns)->namespace_collection);

        signal_t *is_bound = parser.get_bound_signal();

        scoped_ptr_t<local_issue_tracker_t::entry_t> bound_issue_tracker_entry;
        issue_subscription_t bound_subscription(&bound_issue_tracker_entry);
        local_issue_t bound_issue("PORT_CONFLICT", true, strprintf("cannot bind to port %d to serve namespace %s", port, ns_name.c_str()));

        // Don't bother propogating the issue unless we don't immediately connect
        if (!is_bound->is_pulsed()) {

            // Propogates the issue through the cluster
            bound_issue_tracker_entry.init(
                    new local_issue_tracker_t::entry_t(local_issue_tracker, bound_issue));

            // Clears the issue from the cluster when 'is_bound' is pulsed
            bound_subscription.reset(is_bound);
        }

        // Because we block here, the local issue related variables will live
        // for the lifetime of the server.
        interruptor.wait_lazily_unordered();

        logINF("Stopped listening for queries for the namespace '%s' %s on port %d.\n", ns_name.c_str(), uuid_to_str(ns).c_str(), port);
    } catch (interrupted_exc_t) {
        /* pass */
    }

    namespaces_being_handled.erase(ns);

    if (!keepalive.get_drain_signal()->is_pulsed()) {
        /* If we were stopped due to a port change, make sure that a new
        instance of `serve_queries()` gets started with the correct port */
        on_change();
    }
}

#endif /* CLUSTERING_ADMINISTRATION_PARSER_MAKER_TCC_ */
<|endoftext|>


<commit_before>/*
 * The MIT License
 *
 * Copyright 2017-2018 Norwegian University of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <fmicpp/fmi2/xml/DefaultExperiment.hpp>

using namespace fmicpp::fmi2::xml;

void DefaultExperiment::load(ptree &node) {

    startTime = node.get<double>("<xmlattr>.startTime", 0);
    stopTime = node.get<double>("<xmlattr>.stopTime", 0);
    stepSize = node.get<double>("<xmlattr>.stepSize", 1.0/100);
    tolerance = node.get<double>("<xmlattr>.tolerance", 0);

}

std::ostream &fmicpp::fmi2::xml::operator<<(std::ostream &os, const DefaultExperiment &experiment) {
    os << "startTime: " << experiment.startTime << " stopTime: " << experiment.stopTime << " stepSize: "
       << experiment.stepSize << " tolerance: " << experiment.tolerance;
    return os;
}
<commit_msg>cleanup<commit_after>/*
 * The MIT License
 *
 * Copyright 2017-2018 Norwegian University of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <fmicpp/fmi2/xml/DefaultExperiment.hpp>

using namespace fmicpp::fmi2::xml;

void DefaultExperiment::load(ptree &node) {

    startTime = node.get<double>("<xmlattr>.startTime", 0);
    stopTime = node.get<double>("<xmlattr>.stopTime", 0);
    stepSize = node.get<double>("<xmlattr>.stepSize", 1.0/100);
    tolerance = node.get<double>("<xmlattr>.tolerance", 0);

}

std::ostream &operator<<(std::ostream &os, const DefaultExperiment &experiment) {
    os << "startTime: " << experiment.startTime << " stopTime: " << experiment.stopTime << " stepSize: "
       << experiment.stepSize << " tolerance: " << experiment.tolerance;
    return os;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2015, Project OSRM contributors
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.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef DISTANCE_TABLE_HPP
#define DISTANCE_TABLE_HPP

#include "plugin_base.hpp"

#include "../algorithms/object_encoder.hpp"
#include "../data_structures/query_edge.hpp"
#include "../data_structures/search_engine.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../util/json_renderer.hpp"
#include "../util/make_unique.hpp"
#include "../util/string_util.hpp"
#include "../util/timing_util.hpp"

#include <osrm/json_container.hpp>

#include <cstdlib>

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

template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
{
  private:
    std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
    int max_locations_distance_table;

  public:
    explicit DistanceTablePlugin(DataFacadeT *facade, const int max_locations_distance_table)
        : max_locations_distance_table(max_locations_distance_table), descriptor_string("table"),
          facade(facade)
    {
        search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
    }

    virtual ~DistanceTablePlugin() {}

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

    Status HandleRequest(const RouteParameters &route_parameters,
                      osrm::json::Object &json_result) override final
    {
        if (!check_all_coordinates(route_parameters.coordinates))
        {
            json_result.values["status_message"] = "Coordinates are invalid";
            return Status::Error;
        }

        const auto &input_bearings = route_parameters.bearings;
        if (input_bearings.size() > 0 &&
            route_parameters.coordinates.size() != input_bearings.size())
        {
            json_result.values["status_message"] =
                "Number of bearings does not match number of coordinates";
            return Status::Error;
        }

        auto number_of_sources =
            std::count_if(route_parameters.is_source.begin(), route_parameters.is_source.end(),
                          [](const bool is_source)
                          {
                              return is_source;
                          });
        auto number_of_destination =
            std::count_if(route_parameters.is_destination.begin(),
                          route_parameters.is_destination.end(), [](const bool is_destination)
                          {
                              return is_destination;
                          });

        if (max_locations_distance_table > 0 &&
            (number_of_sources * number_of_destination >
             max_locations_distance_table * max_locations_distance_table))
        {
            json_result.values["status_message"] =
                "Number of entries " + std::to_string(number_of_sources * number_of_destination) +
                " is higher than current maximum (" +
                std::to_string(max_locations_distance_table * max_locations_distance_table) + ")";
            return Status::Error;
        }

        const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());

        std::vector<PhantomNodePair> phantom_node_source_vector(number_of_sources);
        std::vector<PhantomNodePair> phantom_node_target_vector(number_of_destination);
        auto phantom_node_source_out_iter = phantom_node_source_vector.begin();
        auto phantom_node_target_out_iter = phantom_node_target_vector.begin();
        for (const auto i : osrm::irange<std::size_t>(0u, route_parameters.coordinates.size()))
        {
            if (checksum_OK && i < route_parameters.hints.size() &&
                !route_parameters.hints[i].empty())
            {
                PhantomNode current_phantom_node;
                ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
                if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
                {
                    if (route_parameters.is_source[i])
                    {
                        *phantom_node_source_out_iter =
                            std::make_pair(current_phantom_node, current_phantom_node);
                        if (route_parameters.is_destination[i])
                        {
                            *phantom_node_target_out_iter = *phantom_node_source_out_iter;
                            phantom_node_target_out_iter++;
                        }
                        phantom_node_source_out_iter++;
                    }
                    else
                    {
                        BOOST_ASSERT(route_parameters.is_destination[i] &&
                                     !route_parameters.is_source[i]);
                        *phantom_node_target_out_iter =
                            std::make_pair(current_phantom_node, current_phantom_node);
                        phantom_node_target_out_iter++;
                    }
                    continue;
                }
            }
            const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
            const int range = input_bearings.size() > 0
                                  ? (input_bearings[i].second ? *input_bearings[i].second : 10)
                                  : 180;
            if (route_parameters.is_source[i])
            {
                *phantom_node_source_out_iter =
                    facade->NearestPhantomNodeWithAlternativeFromBigComponent(
                        route_parameters.coordinates[i], bearing, range);
                // we didn't found a fitting node, return error
                if (!phantom_node_source_out_iter->first.is_valid(facade->GetNumberOfNodes()))
                {
                    json_result.values["status_message"] =
                        std::string("Could not find matching road for via ") + std::to_string(i);
                    return Status::NoSegment;
                }

                if (route_parameters.is_destination[i])
                {
                    *phantom_node_target_out_iter = *phantom_node_source_out_iter;
                    phantom_node_target_out_iter++;
                }
                phantom_node_source_out_iter++;
            }
            else
            {
                BOOST_ASSERT(route_parameters.is_destination[i] && !route_parameters.is_source[i]);

                *phantom_node_target_out_iter =
                    facade->NearestPhantomNodeWithAlternativeFromBigComponent(
                        route_parameters.coordinates[i], bearing, range);
                // we didn't found a fitting node, return error
                if (!phantom_node_target_out_iter->first.is_valid(facade->GetNumberOfNodes()))
                {
                    json_result.values["status_message"] =
                        std::string("Could not find matching road for via ") + std::to_string(i);
                    return Status::NoSegment;
                }
                phantom_node_target_out_iter++;
            }
        }

        BOOST_ASSERT((phantom_node_source_out_iter - phantom_node_source_vector.begin()) ==
                     number_of_sources);
        BOOST_ASSERT((phantom_node_target_out_iter - phantom_node_target_vector.begin()) ==
                     number_of_destination);

        // FIXME we should clear phantom_node_source_vector and phantom_node_target_vector after
        // this
        auto snapped_source_phantoms = snapPhantomNodes(phantom_node_source_vector);
        auto snapped_target_phantoms = snapPhantomNodes(phantom_node_target_vector);

        auto result_table =
            search_engine_ptr->distance_table(snapped_source_phantoms, snapped_target_phantoms);

        if (!result_table)
        {
            json_result.values["status_message"] = "No distance table found";
            return Status::EmptyResult;
        }

        osrm::json::Array matrix_json_array;
        for (const auto row : osrm::irange<std::size_t>(0, number_of_sources))
        {
            osrm::json::Array json_row;
            auto row_begin_iterator = result_table->begin() + (row * number_of_destination);
            auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_destination);
            json_row.values.insert(json_row.values.end(), row_begin_iterator, row_end_iterator);
            matrix_json_array.values.push_back(json_row);
        }
        json_result.values["distance_table"] = matrix_json_array;

        osrm::json::Array target_coord_json_array;
        for (const auto &phantom : snapped_target_phantoms)
        {
            osrm::json::Array json_coord;
            json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
            json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
            target_coord_json_array.values.push_back(json_coord);
        }
        json_result.values["destination_coordinates"] = target_coord_json_array;
        osrm::json::Array source_coord_json_array;
        for (const auto &phantom : snapped_source_phantoms)
        {
            osrm::json::Array json_coord;
            json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
            json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
            source_coord_json_array.values.push_back(json_coord);
        }
        json_result.values["source_coordinates"] = source_coord_json_array;
        return Status::Ok;
    }

  private:
    std::string descriptor_string;
    DataFacadeT *facade;
};

#endif // DISTANCE_TABLE_HPP
<commit_msg>Adjust error string of distance_table to other plugins<commit_after>/*

Copyright (c) 2015, Project OSRM contributors
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.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef DISTANCE_TABLE_HPP
#define DISTANCE_TABLE_HPP

#include "plugin_base.hpp"

#include "../algorithms/object_encoder.hpp"
#include "../data_structures/query_edge.hpp"
#include "../data_structures/search_engine.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../util/json_renderer.hpp"
#include "../util/make_unique.hpp"
#include "../util/string_util.hpp"
#include "../util/timing_util.hpp"

#include <osrm/json_container.hpp>

#include <cstdlib>

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

template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
{
  private:
    std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
    int max_locations_distance_table;

  public:
    explicit DistanceTablePlugin(DataFacadeT *facade, const int max_locations_distance_table)
        : max_locations_distance_table(max_locations_distance_table), descriptor_string("table"),
          facade(facade)
    {
        search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
    }

    virtual ~DistanceTablePlugin() {}

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

    Status HandleRequest(const RouteParameters &route_parameters,
                      osrm::json::Object &json_result) override final
    {
        if (!check_all_coordinates(route_parameters.coordinates))
        {
            json_result.values["status_message"] = "Coordinates are invalid";
            return Status::Error;
        }

        const auto &input_bearings = route_parameters.bearings;
        if (input_bearings.size() > 0 &&
            route_parameters.coordinates.size() != input_bearings.size())
        {
            json_result.values["status_message"] =
                "Number of bearings does not match number of coordinates";
            return Status::Error;
        }

        auto number_of_sources =
            std::count_if(route_parameters.is_source.begin(), route_parameters.is_source.end(),
                          [](const bool is_source)
                          {
                              return is_source;
                          });
        auto number_of_destination =
            std::count_if(route_parameters.is_destination.begin(),
                          route_parameters.is_destination.end(), [](const bool is_destination)
                          {
                              return is_destination;
                          });

        if (max_locations_distance_table > 0 &&
            (number_of_sources * number_of_destination >
             max_locations_distance_table * max_locations_distance_table))
        {
            json_result.values["status_message"] =
                "Number of entries " + std::to_string(number_of_sources * number_of_destination) +
                " is higher than current maximum (" +
                std::to_string(max_locations_distance_table * max_locations_distance_table) + ")";
            return Status::Error;
        }

        const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());

        std::vector<PhantomNodePair> phantom_node_source_vector(number_of_sources);
        std::vector<PhantomNodePair> phantom_node_target_vector(number_of_destination);
        auto phantom_node_source_out_iter = phantom_node_source_vector.begin();
        auto phantom_node_target_out_iter = phantom_node_target_vector.begin();
        for (const auto i : osrm::irange<std::size_t>(0u, route_parameters.coordinates.size()))
        {
            if (checksum_OK && i < route_parameters.hints.size() &&
                !route_parameters.hints[i].empty())
            {
                PhantomNode current_phantom_node;
                ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
                if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
                {
                    if (route_parameters.is_source[i])
                    {
                        *phantom_node_source_out_iter =
                            std::make_pair(current_phantom_node, current_phantom_node);
                        if (route_parameters.is_destination[i])
                        {
                            *phantom_node_target_out_iter = *phantom_node_source_out_iter;
                            phantom_node_target_out_iter++;
                        }
                        phantom_node_source_out_iter++;
                    }
                    else
                    {
                        BOOST_ASSERT(route_parameters.is_destination[i] &&
                                     !route_parameters.is_source[i]);
                        *phantom_node_target_out_iter =
                            std::make_pair(current_phantom_node, current_phantom_node);
                        phantom_node_target_out_iter++;
                    }
                    continue;
                }
            }
            const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
            const int range = input_bearings.size() > 0
                                  ? (input_bearings[i].second ? *input_bearings[i].second : 10)
                                  : 180;
            if (route_parameters.is_source[i])
            {
                *phantom_node_source_out_iter =
                    facade->NearestPhantomNodeWithAlternativeFromBigComponent(
                        route_parameters.coordinates[i], bearing, range);
                // we didn't found a fitting node, return error
                if (!phantom_node_source_out_iter->first.is_valid(facade->GetNumberOfNodes()))
                {
                    json_result.values["status_message"] =
                        std::string("Could not find a matching segment for coordinate ") + std::to_string(i);
                    return Status::NoSegment;
                }

                if (route_parameters.is_destination[i])
                {
                    *phantom_node_target_out_iter = *phantom_node_source_out_iter;
                    phantom_node_target_out_iter++;
                }
                phantom_node_source_out_iter++;
            }
            else
            {
                BOOST_ASSERT(route_parameters.is_destination[i] && !route_parameters.is_source[i]);

                *phantom_node_target_out_iter =
                    facade->NearestPhantomNodeWithAlternativeFromBigComponent(
                        route_parameters.coordinates[i], bearing, range);
                // we didn't found a fitting node, return error
                if (!phantom_node_target_out_iter->first.is_valid(facade->GetNumberOfNodes()))
                {
                    json_result.values["status_message"] =
                        std::string("Could not find a matching segment for coordinate ") + std::to_string(i);
                    return Status::NoSegment;
                }
                phantom_node_target_out_iter++;
            }
        }

        BOOST_ASSERT((phantom_node_source_out_iter - phantom_node_source_vector.begin()) ==
                     number_of_sources);
        BOOST_ASSERT((phantom_node_target_out_iter - phantom_node_target_vector.begin()) ==
                     number_of_destination);

        // FIXME we should clear phantom_node_source_vector and phantom_node_target_vector after
        // this
        auto snapped_source_phantoms = snapPhantomNodes(phantom_node_source_vector);
        auto snapped_target_phantoms = snapPhantomNodes(phantom_node_target_vector);

        auto result_table =
            search_engine_ptr->distance_table(snapped_source_phantoms, snapped_target_phantoms);

        if (!result_table)
        {
            json_result.values["status_message"] = "No distance table found";
            return Status::EmptyResult;
        }

        osrm::json::Array matrix_json_array;
        for (const auto row : osrm::irange<std::size_t>(0, number_of_sources))
        {
            osrm::json::Array json_row;
            auto row_begin_iterator = result_table->begin() + (row * number_of_destination);
            auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_destination);
            json_row.values.insert(json_row.values.end(), row_begin_iterator, row_end_iterator);
            matrix_json_array.values.push_back(json_row);
        }
        json_result.values["distance_table"] = matrix_json_array;

        osrm::json::Array target_coord_json_array;
        for (const auto &phantom : snapped_target_phantoms)
        {
            osrm::json::Array json_coord;
            json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
            json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
            target_coord_json_array.values.push_back(json_coord);
        }
        json_result.values["destination_coordinates"] = target_coord_json_array;
        osrm::json::Array source_coord_json_array;
        for (const auto &phantom : snapped_source_phantoms)
        {
            osrm::json::Array json_coord;
            json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
            json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
            source_coord_json_array.values.push_back(json_coord);
        }
        json_result.values["source_coordinates"] = source_coord_json_array;
        return Status::Ok;
    }

  private:
    std::string descriptor_string;
    DataFacadeT *facade;
};

#endif // DISTANCE_TABLE_HPP
<|endoftext|>