<commit_before>/***********************************************************************************************************************
 *
 * Copyright (c) 2015, ABB Schweiz AG
 * 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 ABB nor the names of its
 *      contributors may be used to endorse or promote
 *      products derived from this software without
 *      specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL 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.
 *
 ***********************************************************************************************************************
 */

#include <sstream>

#include "abb_libegm/egm_common_auxiliary.h"
#include "abb_libegm/egm_controller_interface.h"

namespace abb
{
namespace egm
{
/***********************************************************************************************************************
 * Class definitions: EGMControllerInterface::ControllerMotion
 */

/************************************************************
 * Primary methods
 */

void EGMControllerInterface::ControllerMotion::initialize(const bool first_message)
{
  if (first_message)
  {
    boost::lock_guard<boost::mutex> lock(read_mutex_);
    boost::lock_guard<boost::mutex> lock2(write_mutex_);

    read_data_ready_ = false;
    write_data_ready_ = false;
  }
}

void EGMControllerInterface::ControllerMotion::writeInputs(const wrapper::Input& inputs)
{
 boost::lock_guard<boost::mutex> lock(read_mutex_);

 inputs_.CopyFrom(inputs);

 read_data_ready_ = true;
 read_condition_variable_.notify_all();
}

void EGMControllerInterface::ControllerMotion::readOutputs(wrapper::Output* p_outputs)
{
  bool timed_out = false;

  boost::unique_lock<boost::mutex> lock(write_mutex_);

  while (!write_data_ready_ && !timed_out)
  {
    timed_out = !write_condition_variable_.timed_wait(lock, boost::posix_time::milliseconds(WRITE_TIMEOUT_MS));
  }

  if (!timed_out && p_outputs)
  {
    copyPresent(p_outputs, outputs_);
    write_data_ready_ = false;
  }
}

bool EGMControllerInterface::ControllerMotion::waitForMessage(const unsigned int timeout_ms)
{
  boost::unique_lock<boost::mutex> lock(read_mutex_);

  bool timed_out = false;

  while (!read_data_ready_ && !timed_out)
  {
    if (timeout_ms <= 0)
    {
      read_condition_variable_.wait(lock);
    }
    else
    {
      timed_out = !read_condition_variable_.timed_wait(lock, boost::posix_time::milliseconds(timeout_ms));
    }
  }

  return !timed_out;
}

void EGMControllerInterface::ControllerMotion::readInputs(wrapper::Input* p_inputs)
{
  boost::lock_guard<boost::mutex> lock(read_mutex_);

  p_inputs->CopyFrom(inputs_);
  read_data_ready_ = false;
}

void EGMControllerInterface::ControllerMotion::writeOutputs(const wrapper::Output& outputs)
{
  boost::lock_guard<boost::mutex> lock(write_mutex_);

  outputs_.CopyFrom(outputs);

  write_data_ready_ = true;
  write_condition_variable_.notify_all();
}

/***********************************************************************************************************************
 * Class definitions: EGMControllerInterface
 */

/************************************************************
 * Primary methods
 */

EGMControllerInterface::EGMControllerInterface(boost::asio::io_service& io_service,
                                               const unsigned short port_number,
                                               const BaseConfiguration& configuration)
:
EGMBaseInterface(io_service, port_number, configuration)
{
  if (configuration_.active.use_logging)
  {
    std::stringstream ss;
    ss << "port_" << port_number << +"_log.csv";
    p_logger_.reset(new EGMLogger(ss.str()));
  }
}

const std::string& EGMControllerInterface::callback(const UDPServerData& server_data)
{
  // Initialize the callback by:
  // - Parsing and extracting data from the recieved message.
  // - Updating any pending configuration changes.
  // - Preparing the outputs.
  if (initializeCallback(server_data))
  {
    // Additional initialization for direct motion references.
    controller_motion_.initialize(inputs_.isFirstMessage());

    // Handle demo execution or external controller execution.
    if (configuration_.active.use_demo_outputs)
    {
      outputs_.generateDemoOutputs(inputs_);
    }
    else
    {
      if (inputs_.isFirstMessage() || inputs_.statesOk())
      {
        // Make the current inputs available (to the external control loop), and notify that it is available.
        controller_motion_.writeInputs(inputs_.current());

        // Wait for new outputs (from the external control loop), or until a timeout occurs.
        controller_motion_.readOutputs(&outputs_.current);
      }
    }

    // Log inputs and outputs, if set to do so.
    if (configuration_.active.use_logging && p_logger_)
    {
      logData(inputs_, outputs_, configuration_.active.max_logging_duration);
    }

    // Constuct the reply message.
    outputs_.constructReply(configuration_.active);

    // Prepare for the next callback.
    inputs_.updatePrevious();
    outputs_.updatePrevious();
  }

  // Return the reply.
  return outputs_.reply();
}

/************************************************************
 * User interaction methods
 */

bool EGMControllerInterface::waitForMessage(const unsigned int timeout_ms)
{
  return controller_motion_.waitForMessage(timeout_ms);
}

void EGMControllerInterface::read(wrapper::Input* p_inputs)
{
  controller_motion_.readInputs(p_inputs);
}

void EGMControllerInterface::write(const wrapper::Output& outputs)
{
  controller_motion_.writeOutputs(outputs);
}

} // end namespace egm
} // end namespace abb
<commit_msg>Make EGMControllerInterface always pass feedback to user<commit_after>/***********************************************************************************************************************
 *
 * Copyright (c) 2015, ABB Schweiz AG
 * 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 ABB nor the names of its
 *      contributors may be used to endorse or promote
 *      products derived from this software without
 *      specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL 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.
 *
 ***********************************************************************************************************************
 */

#include <sstream>

#include "abb_libegm/egm_common_auxiliary.h"
#include "abb_libegm/egm_controller_interface.h"

namespace abb
{
namespace egm
{
/***********************************************************************************************************************
 * Class definitions: EGMControllerInterface::ControllerMotion
 */

/************************************************************
 * Primary methods
 */

void EGMControllerInterface::ControllerMotion::initialize(const bool first_message)
{
  if (first_message)
  {
    boost::lock_guard<boost::mutex> lock(read_mutex_);
    boost::lock_guard<boost::mutex> lock2(write_mutex_);

    read_data_ready_ = false;
    write_data_ready_ = false;
  }
}

void EGMControllerInterface::ControllerMotion::writeInputs(const wrapper::Input& inputs)
{
 boost::lock_guard<boost::mutex> lock(read_mutex_);

 inputs_.CopyFrom(inputs);

 read_data_ready_ = true;
 read_condition_variable_.notify_all();
}

void EGMControllerInterface::ControllerMotion::readOutputs(wrapper::Output* p_outputs)
{
  bool timed_out = false;

  boost::unique_lock<boost::mutex> lock(write_mutex_);

  while (!write_data_ready_ && !timed_out)
  {
    timed_out = !write_condition_variable_.timed_wait(lock, boost::posix_time::milliseconds(WRITE_TIMEOUT_MS));
  }

  if (!timed_out && p_outputs)
  {
    copyPresent(p_outputs, outputs_);
    write_data_ready_ = false;
  }
}

bool EGMControllerInterface::ControllerMotion::waitForMessage(const unsigned int timeout_ms)
{
  boost::unique_lock<boost::mutex> lock(read_mutex_);

  bool timed_out = false;

  while (!read_data_ready_ && !timed_out)
  {
    if (timeout_ms <= 0)
    {
      read_condition_variable_.wait(lock);
    }
    else
    {
      timed_out = !read_condition_variable_.timed_wait(lock, boost::posix_time::milliseconds(timeout_ms));
    }
  }

  return !timed_out;
}

void EGMControllerInterface::ControllerMotion::readInputs(wrapper::Input* p_inputs)
{
  boost::lock_guard<boost::mutex> lock(read_mutex_);

  p_inputs->CopyFrom(inputs_);
  read_data_ready_ = false;
}

void EGMControllerInterface::ControllerMotion::writeOutputs(const wrapper::Output& outputs)
{
  boost::lock_guard<boost::mutex> lock(write_mutex_);

  outputs_.CopyFrom(outputs);

  write_data_ready_ = true;
  write_condition_variable_.notify_all();
}

/***********************************************************************************************************************
 * Class definitions: EGMControllerInterface
 */

/************************************************************
 * Primary methods
 */

EGMControllerInterface::EGMControllerInterface(boost::asio::io_service& io_service,
                                               const unsigned short port_number,
                                               const BaseConfiguration& configuration)
:
EGMBaseInterface(io_service, port_number, configuration)
{
  if (configuration_.active.use_logging)
  {
    std::stringstream ss;
    ss << "port_" << port_number << +"_log.csv";
    p_logger_.reset(new EGMLogger(ss.str()));
  }
}

const std::string& EGMControllerInterface::callback(const UDPServerData& server_data)
{
  // Initialize the callback by:
  // - Parsing and extracting data from the recieved message.
  // - Updating any pending configuration changes.
  // - Preparing the outputs.
  if (initializeCallback(server_data))
  {
    // Additional initialization for direct motion references.
    controller_motion_.initialize(inputs_.isFirstMessage());

    // Handle demo execution or external controller execution.
    if (configuration_.active.use_demo_outputs)
    {
      outputs_.generateDemoOutputs(inputs_);
    }
    else
    {
      // Make the current inputs available (to the external control loop), and notify that it is available.
      controller_motion_.writeInputs(inputs_.current());

      if (inputs_.isFirstMessage() || inputs_.statesOk())
      {
        // Wait for new outputs (from the external control loop), or until a timeout occurs.
        controller_motion_.readOutputs(&outputs_.current);
      }
    }

    // Log inputs and outputs, if set to do so.
    if (configuration_.active.use_logging && p_logger_)
    {
      logData(inputs_, outputs_, configuration_.active.max_logging_duration);
    }

    // Constuct the reply message.
    outputs_.constructReply(configuration_.active);

    // Prepare for the next callback.
    inputs_.updatePrevious();
    outputs_.updatePrevious();
  }

  // Return the reply.
  return outputs_.reply();
}

/************************************************************
 * User interaction methods
 */

bool EGMControllerInterface::waitForMessage(const unsigned int timeout_ms)
{
  return controller_motion_.waitForMessage(timeout_ms);
}

void EGMControllerInterface::read(wrapper::Input* p_inputs)
{
  controller_motion_.readInputs(p_inputs);
}

void EGMControllerInterface::write(const wrapper::Output& outputs)
{
  controller_motion_.writeOutputs(outputs);
}

} // end namespace egm
} // end namespace abb
<|endoftext|>


<commit_before>//
// Copyright (C)  2005-2022 Greg Landrum and other RDKit contributors
//
//  @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#include "RDLog.h"

#if 1
#include <iomanip>
#include <string>
#include <ctime>
#include <iostream>
#include <sstream>

RDLogger rdAppLog = nullptr;
RDLogger rdDebugLog = nullptr;
RDLogger rdInfoLog = nullptr;
RDLogger rdErrorLog = nullptr;
RDLogger rdWarningLog = nullptr;
RDLogger rdStatusLog = nullptr;
namespace RDLog {

namespace {
const std::vector<RDLogger *> allLogs = {&rdAppLog,     &rdDebugLog,
                                         &rdInfoLog,    &rdErrorLog,
                                         &rdWarningLog, &rdStatusLog};
}

LogStateSetter::LogStateSetter() {
  for (auto i = 0u; i < allLogs.size(); ++i) {
    if (*allLogs[i] && (*allLogs[i])->df_enabled) {
      d_origState |= 1 << i;
      (*allLogs[i])->df_enabled = false;
    }
  }
}

LogStateSetter::LogStateSetter(RDLoggerList toEnable) : LogStateSetter() {
  for (auto i = 0u; i < allLogs.size(); ++i) {
    if (*allLogs[i] && std::find(toEnable.begin(), toEnable.end(),
                                 *allLogs[i]) != toEnable.end()) {
      d_origState ^= 1 << i;
      (*allLogs[i])->df_enabled = true;
    }
  }
}

LogStateSetter::~LogStateSetter() {
  for (auto i = 0u; i < allLogs.size(); ++i) {
    if (*allLogs[i]) {
      (*allLogs[i])->df_enabled ^= d_origState >> i & 1;
    }
  }
}
}  // namespace RDLog
namespace boost {
namespace logging {

void enable_logs(const char *arg) { enable_logs(std::string(arg)); };
void enable_logs(const std::string &arg) {
  // Yes... this is extremely crude
  if (arg == "rdApp.debug" || arg == "rdApp.*") {
    if (rdDebugLog) {
      rdDebugLog->df_enabled = true;
    }
  }
  if (arg == "rdApp.info" || arg == "rdApp.*") {
    if (rdInfoLog) {
      rdInfoLog->df_enabled = true;
    }
  }
  if (arg == "rdApp.warning" || arg == "rdApp.*") {
    if (rdWarningLog) {
      rdWarningLog->df_enabled = true;
    }
  }
  if (arg == "rdApp.error" || arg == "rdApp.*") {
    if (rdErrorLog) {
      rdErrorLog->df_enabled = true;
    }
  }
};
void disable_logs(const char *arg) { disable_logs(std::string(arg)); };
void disable_logs(const std::string &arg) {
  // Yes... this is extremely crude
  if (arg == "rdApp.debug" || arg == "rdApp.*") {
    if (rdDebugLog) {
      rdDebugLog->df_enabled = false;
    }
  }
  if (arg == "rdApp.info" || arg == "rdApp.*") {
    if (rdInfoLog) {
      rdInfoLog->df_enabled = false;
    }
  }
  if (arg == "rdApp.warning" || arg == "rdApp.*") {
    if (rdWarningLog) {
      rdWarningLog->df_enabled = false;
    }
  }
  if (arg == "rdApp.error" || arg == "rdApp.*") {
    if (rdErrorLog) {
      rdErrorLog->df_enabled = false;
    }
  }
};

bool is_log_enabled(RDLogger log) { return log && log->df_enabled; }

void get_log_status(std::ostream &ss, const std::string &name, RDLogger log) {
  ss << name << ":";
  if (log) {
    if (log->df_enabled) {
      ss << "enabled";
    } else {
      ss << "disabled";
    }
  } else {
    ss << "unitialized";
  }
}

std::string log_status() {
  std::stringstream ss;
  get_log_status(ss, "rdApp.debug", rdDebugLog);
  ss << std::endl;
  get_log_status(ss, "rdApp.info", rdInfoLog);
  ss << std::endl;
  get_log_status(ss, "rdApp.warning", rdWarningLog);
  ss << std::endl;
  get_log_status(ss, "rdApp.error", rdErrorLog);
  return ss.str();
}

}  // namespace logging
}  // namespace boost

namespace RDLog {
void InitLogs() {
  rdDebugLog = std::make_shared<boost::logging::rdLogger>(&std::cerr);
  rdDebugLog->df_enabled = false;
  rdInfoLog = std::make_shared<boost::logging::rdLogger>(&std::cout);
  rdInfoLog->df_enabled = false;
  rdWarningLog = std::make_shared<boost::logging::rdLogger>(&std::cerr);
  rdErrorLog = std::make_shared<boost::logging::rdLogger>(&std::cerr);
}

std::ostream &toStream(std::ostream &logstrm) {
  char buffer[16];
  time_t t = time(nullptr);
  strftime(buffer, 16, "[%T] ", localtime(&t));
  return logstrm << buffer;
}
}  // namespace RDLog

#else
#include <boost/log/functions.hpp>
#if defined(BOOST_HAS_THREADS2)
#include <boost/log/extra/functions_ts.hpp>
#endif
#include <iostream>
namespace logging = boost::logging;

BOOST_DEFINE_LOG(rdAppLog, "rdApp")
BOOST_DEFINE_LOG(rdDebugLog, "rdApp.debug")
BOOST_DEFINE_LOG(rdInfoLog, "rdApp.info")
BOOST_DEFINE_LOG(rdErrorLog, "rdApp.error")
BOOST_DEFINE_LOG(rdWarningLog, "rdApp.warning")
BOOST_DEFINE_LOG(rdStatusLog, "rdApp.status")

namespace RDLog {
void write_to_cout(const std::string &, const std::string &msg) {
  std::cout << msg;
  std::cout.flush();
}
void write_to_cerr(const std::string &, const std::string &msg) {
  std::cerr << msg;
  std::cerr.flush();
}

void InitLogs() {
  static bool callOnce = true;
  if (!callOnce) return;
  callOnce = false;

  // turn off caching:
  logging::set_log_caching(false);
  logging::manipulate_logs("rdApp.*").add_modifier(
      logging::prepend_time("[$hh:$mm:$ss] "), logging::DEFAULT_INDEX - 10);
  logging::manipulate_logs("rdApp.info")
      .add_appender(write_to_cout, logging::DEFAULT_INDEX + 1);
#if defined(BOOST_HAS_THREADS2)
  logging::manipulate_logs("rdApp.error")
      .add_appender(logging::ts_appender(write_to_cerr, 100),
                    logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.warning")
      .add_appender(logging::ts_appender(write_to_cerr, 100),
                    logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.status")
      .add_appender(logging::ts_appender(write_to_cerr, 100),
                    logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.debug")
      .add_appender(logging::ts_appender(write_to_cerr, 100),
                    logging::DEFAULT_INDEX + 1);
#else
  logging::manipulate_logs("rdApp.error")
      .add_appender(write_to_cerr, logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.warning")
      .add_appender(write_to_cerr, logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.status")
      .add_appender(write_to_cerr, logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.debug")
      .add_appender(write_to_cerr, logging::DEFAULT_INDEX + 1);
#endif
  // start with the debug log disabled:
  logging::disable_logs("rdApp.debug");
};

}  // namespace RDLog
#endif
<commit_msg>Fix use of not thread safe function localtime()  (#5211)<commit_after>//
// Copyright (C)  2005-2022 Greg Landrum and other RDKit contributors
//
//  @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#include "RDLog.h"

#if 1
#include <iomanip>
#include <string>
#include <ctime>
#include <iostream>
#include <sstream>

RDLogger rdAppLog = nullptr;
RDLogger rdDebugLog = nullptr;
RDLogger rdInfoLog = nullptr;
RDLogger rdErrorLog = nullptr;
RDLogger rdWarningLog = nullptr;
RDLogger rdStatusLog = nullptr;
namespace RDLog {

namespace {
const std::vector<RDLogger *> allLogs = {&rdAppLog,     &rdDebugLog,
                                         &rdInfoLog,    &rdErrorLog,
                                         &rdWarningLog, &rdStatusLog};
}

LogStateSetter::LogStateSetter() {
  for (auto i = 0u; i < allLogs.size(); ++i) {
    if (*allLogs[i] && (*allLogs[i])->df_enabled) {
      d_origState |= 1 << i;
      (*allLogs[i])->df_enabled = false;
    }
  }
}

LogStateSetter::LogStateSetter(RDLoggerList toEnable) : LogStateSetter() {
  for (auto i = 0u; i < allLogs.size(); ++i) {
    if (*allLogs[i] && std::find(toEnable.begin(), toEnable.end(),
                                 *allLogs[i]) != toEnable.end()) {
      d_origState ^= 1 << i;
      (*allLogs[i])->df_enabled = true;
    }
  }
}

LogStateSetter::~LogStateSetter() {
  for (auto i = 0u; i < allLogs.size(); ++i) {
    if (*allLogs[i]) {
      (*allLogs[i])->df_enabled ^= d_origState >> i & 1;
    }
  }
}
}  // namespace RDLog
namespace boost {
namespace logging {

void enable_logs(const char *arg) { enable_logs(std::string(arg)); };
void enable_logs(const std::string &arg) {
  // Yes... this is extremely crude
  if (arg == "rdApp.debug" || arg == "rdApp.*") {
    if (rdDebugLog) {
      rdDebugLog->df_enabled = true;
    }
  }
  if (arg == "rdApp.info" || arg == "rdApp.*") {
    if (rdInfoLog) {
      rdInfoLog->df_enabled = true;
    }
  }
  if (arg == "rdApp.warning" || arg == "rdApp.*") {
    if (rdWarningLog) {
      rdWarningLog->df_enabled = true;
    }
  }
  if (arg == "rdApp.error" || arg == "rdApp.*") {
    if (rdErrorLog) {
      rdErrorLog->df_enabled = true;
    }
  }
};
void disable_logs(const char *arg) { disable_logs(std::string(arg)); };
void disable_logs(const std::string &arg) {
  // Yes... this is extremely crude
  if (arg == "rdApp.debug" || arg == "rdApp.*") {
    if (rdDebugLog) {
      rdDebugLog->df_enabled = false;
    }
  }
  if (arg == "rdApp.info" || arg == "rdApp.*") {
    if (rdInfoLog) {
      rdInfoLog->df_enabled = false;
    }
  }
  if (arg == "rdApp.warning" || arg == "rdApp.*") {
    if (rdWarningLog) {
      rdWarningLog->df_enabled = false;
    }
  }
  if (arg == "rdApp.error" || arg == "rdApp.*") {
    if (rdErrorLog) {
      rdErrorLog->df_enabled = false;
    }
  }
};

bool is_log_enabled(RDLogger log) { return log && log->df_enabled; }

void get_log_status(std::ostream &ss, const std::string &name, RDLogger log) {
  ss << name << ":";
  if (log) {
    if (log->df_enabled) {
      ss << "enabled";
    } else {
      ss << "disabled";
    }
  } else {
    ss << "unitialized";
  }
}

std::string log_status() {
  std::stringstream ss;
  get_log_status(ss, "rdApp.debug", rdDebugLog);
  ss << std::endl;
  get_log_status(ss, "rdApp.info", rdInfoLog);
  ss << std::endl;
  get_log_status(ss, "rdApp.warning", rdWarningLog);
  ss << std::endl;
  get_log_status(ss, "rdApp.error", rdErrorLog);
  return ss.str();
}

}  // namespace logging
}  // namespace boost

namespace RDLog {
void InitLogs() {
  rdDebugLog = std::make_shared<boost::logging::rdLogger>(&std::cerr);
  rdDebugLog->df_enabled = false;
  rdInfoLog = std::make_shared<boost::logging::rdLogger>(&std::cout);
  rdInfoLog->df_enabled = false;
  rdWarningLog = std::make_shared<boost::logging::rdLogger>(&std::cerr);
  rdErrorLog = std::make_shared<boost::logging::rdLogger>(&std::cerr);
}

std::ostream &toStream(std::ostream &logstrm) {
  char buffer[16];
  time_t t = time(nullptr);
  struct tm *tm;
// localtime() is thread safe on windows, but not on *nix
#ifdef WIN32
  strftime(buffer, 16, "[%T] ", localtime(&t));
#else
  struct tm buf;
  strftime(buffer, 16, "[%T] ", localtime_r(&t, &buf));
#endif
  return logstrm << buffer;
}
}  // namespace RDLog

#else
#include <boost/log/functions.hpp>
#if defined(BOOST_HAS_THREADS2)
#include <boost/log/extra/functions_ts.hpp>
#endif
#include <iostream>
namespace logging = boost::logging;

BOOST_DEFINE_LOG(rdAppLog, "rdApp")
BOOST_DEFINE_LOG(rdDebugLog, "rdApp.debug")
BOOST_DEFINE_LOG(rdInfoLog, "rdApp.info")
BOOST_DEFINE_LOG(rdErrorLog, "rdApp.error")
BOOST_DEFINE_LOG(rdWarningLog, "rdApp.warning")
BOOST_DEFINE_LOG(rdStatusLog, "rdApp.status")

namespace RDLog {
void write_to_cout(const std::string &, const std::string &msg) {
  std::cout << msg;
  std::cout.flush();
}
void write_to_cerr(const std::string &, const std::string &msg) {
  std::cerr << msg;
  std::cerr.flush();
}

void InitLogs() {
  static bool callOnce = true;
  if (!callOnce) return;
  callOnce = false;

  // turn off caching:
  logging::set_log_caching(false);
  logging::manipulate_logs("rdApp.*").add_modifier(
      logging::prepend_time("[$hh:$mm:$ss] "), logging::DEFAULT_INDEX - 10);
  logging::manipulate_logs("rdApp.info")
      .add_appender(write_to_cout, logging::DEFAULT_INDEX + 1);
#if defined(BOOST_HAS_THREADS2)
  logging::manipulate_logs("rdApp.error")
      .add_appender(logging::ts_appender(write_to_cerr, 100),
                    logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.warning")
      .add_appender(logging::ts_appender(write_to_cerr, 100),
                    logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.status")
      .add_appender(logging::ts_appender(write_to_cerr, 100),
                    logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.debug")
      .add_appender(logging::ts_appender(write_to_cerr, 100),
                    logging::DEFAULT_INDEX + 1);
#else
  logging::manipulate_logs("rdApp.error")
      .add_appender(write_to_cerr, logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.warning")
      .add_appender(write_to_cerr, logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.status")
      .add_appender(write_to_cerr, logging::DEFAULT_INDEX + 1);
  logging::manipulate_logs("rdApp.debug")
      .add_appender(write_to_cerr, logging::DEFAULT_INDEX + 1);
#endif
  // start with the debug log disabled:
  logging::disable_logs("rdApp.debug");
};

}  // namespace RDLog
#endif
<|endoftext|>


<commit_before>//===--- SILLayout.cpp - Defines SIL-level aggregate layouts ----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines classes that describe the physical layout of nominal
// types in SIL, including structs, classes, and boxes. This is distinct from
// the AST-level layout for several reasons:
// - It avoids redundant work lowering the layout of aggregates from the AST.
// - It allows optimizations to manipulate the layout of aggregates without
//   requiring changes to the AST. For instance, optimizations can eliminate
//   dead fields from instances or turn invariant fields into global variables.
// - It allows for SIL-only aggregates to exist, such as boxes.
// - It improves the robustness of code in the face of resilience. A resilient
//   type can be modeled in SIL as not having a layout at all, preventing the
//   inappropriate use of fragile projection and injection operations on the
//   type.
//
//===----------------------------------------------------------------------===//

#include "swift/SIL/SILLayout.h"
#include "swift/SIL/SILModule.h"

using namespace swift;

static bool anyMutable(ArrayRef<SILField> Fields) {
  for (auto &field : Fields) {
    if (field.isMutable())
      return true;
  }
  return false;
}

SILLayout *SILLayout::get(ASTContext &C,
                          CanGenericSignature Generics,
                          ArrayRef<SILField> Fields) {
  // Profile the layout parameters.
  llvm::FoldingSetNodeID id;
  Profile(id, Generics, Fields);

  // Return an existing layout if there is one.
  void *insertPos;
  auto *&Layouts = C.getSILLayouts();
  if (!Layouts)
    Layouts = new llvm::FoldingSet<SILLayout>;

  if (auto existing = Layouts->FindNodeOrInsertPos(id, insertPos))
    return existing;

  // Allocate a new layout.
  void *memory = C.Allocate(totalSizeToAlloc<SILField>(Fields.size()),
                            alignof(SILLayout));

  auto newLayout = ::new (memory) SILLayout(Generics, Fields);
  Layouts->InsertNode(newLayout, insertPos);
  return newLayout;
}

#ifndef NDEBUG
/// Verify that the types of fields are valid within a given generic signature.
static void verifyFields(CanGenericSignature Sig, ArrayRef<SILField> Fields) {
  for (auto &field : Fields) {
    auto ty = field.getLoweredType();
    // Layouts should never refer to archetypes, since they represent an
    // abstract generic type layout.
    assert(!ty->hasArchetype()
           && "SILLayout field cannot have an archetype type");
    assert(!ty->hasTypeVariable()
           && "SILLayout cannot contain constraint system type variables");
    if (!ty->hasTypeParameter())
      continue;
    field.getLoweredType().findIf([Sig](Type t) -> bool {
      if (auto gpt = t->getAs<GenericTypeParamType>()) {
        // Check that the generic param exists in the generic signature.
        assert(Sig && "generic param in nongeneric layout?");
        assert(std::find(Sig.getGenericParams().begin(),
                         Sig.getGenericParams().end(),
                         gpt->getCanonicalType()) != Sig.getGenericParams().end()
               && "generic param not declared in generic signature?!");
      }
      return false;
    });
  }
}
#endif

SILLayout::SILLayout(CanGenericSignature Sig,
                     ArrayRef<SILField> Fields)
  : GenericSigAndFlags(Sig, getFlagsValue(anyMutable(Fields))),
    NumFields(Fields.size())
{
#ifndef NDEBUG
  verifyFields(Sig, Fields);
#endif
  auto FieldsMem = getTrailingObjects<SILField>();
  for (unsigned i : indices(Fields)) {
    new (FieldsMem) SILField(Fields[i]);
  }
}

void SILLayout::Profile(llvm::FoldingSetNodeID &id,
                        CanGenericSignature Generics,
                        ArrayRef<SILField> Fields) {
  id.AddPointer(Generics.getPointer());
  for (auto &field : Fields) {
    id.AddPointer(field.getLoweredType().getPointer());
    id.AddBoolean(field.isMutable());
  }
}
<commit_msg>[gardening] Fix header inconsistency: C++ marker not needed for .cpp files.<commit_after>//===--- SILLayout.cpp - Defines SIL-level aggregate layouts --------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines classes that describe the physical layout of nominal
// types in SIL, including structs, classes, and boxes. This is distinct from
// the AST-level layout for several reasons:
// - It avoids redundant work lowering the layout of aggregates from the AST.
// - It allows optimizations to manipulate the layout of aggregates without
//   requiring changes to the AST. For instance, optimizations can eliminate
//   dead fields from instances or turn invariant fields into global variables.
// - It allows for SIL-only aggregates to exist, such as boxes.
// - It improves the robustness of code in the face of resilience. A resilient
//   type can be modeled in SIL as not having a layout at all, preventing the
//   inappropriate use of fragile projection and injection operations on the
//   type.
//
//===----------------------------------------------------------------------===//

#include "swift/SIL/SILLayout.h"
#include "swift/SIL/SILModule.h"

using namespace swift;

static bool anyMutable(ArrayRef<SILField> Fields) {
  for (auto &field : Fields) {
    if (field.isMutable())
      return true;
  }
  return false;
}

SILLayout *SILLayout::get(ASTContext &C,
                          CanGenericSignature Generics,
                          ArrayRef<SILField> Fields) {
  // Profile the layout parameters.
  llvm::FoldingSetNodeID id;
  Profile(id, Generics, Fields);

  // Return an existing layout if there is one.
  void *insertPos;
  auto *&Layouts = C.getSILLayouts();
  if (!Layouts)
    Layouts = new llvm::FoldingSet<SILLayout>;

  if (auto existing = Layouts->FindNodeOrInsertPos(id, insertPos))
    return existing;

  // Allocate a new layout.
  void *memory = C.Allocate(totalSizeToAlloc<SILField>(Fields.size()),
                            alignof(SILLayout));

  auto newLayout = ::new (memory) SILLayout(Generics, Fields);
  Layouts->InsertNode(newLayout, insertPos);
  return newLayout;
}

#ifndef NDEBUG
/// Verify that the types of fields are valid within a given generic signature.
static void verifyFields(CanGenericSignature Sig, ArrayRef<SILField> Fields) {
  for (auto &field : Fields) {
    auto ty = field.getLoweredType();
    // Layouts should never refer to archetypes, since they represent an
    // abstract generic type layout.
    assert(!ty->hasArchetype()
           && "SILLayout field cannot have an archetype type");
    assert(!ty->hasTypeVariable()
           && "SILLayout cannot contain constraint system type variables");
    if (!ty->hasTypeParameter())
      continue;
    field.getLoweredType().findIf([Sig](Type t) -> bool {
      if (auto gpt = t->getAs<GenericTypeParamType>()) {
        // Check that the generic param exists in the generic signature.
        assert(Sig && "generic param in nongeneric layout?");
        assert(std::find(Sig.getGenericParams().begin(),
                         Sig.getGenericParams().end(),
                         gpt->getCanonicalType()) != Sig.getGenericParams().end()
               && "generic param not declared in generic signature?!");
      }
      return false;
    });
  }
}
#endif

SILLayout::SILLayout(CanGenericSignature Sig,
                     ArrayRef<SILField> Fields)
  : GenericSigAndFlags(Sig, getFlagsValue(anyMutable(Fields))),
    NumFields(Fields.size())
{
#ifndef NDEBUG
  verifyFields(Sig, Fields);
#endif
  auto FieldsMem = getTrailingObjects<SILField>();
  for (unsigned i : indices(Fields)) {
    new (FieldsMem) SILField(Fields[i]);
  }
}

void SILLayout::Profile(llvm::FoldingSetNodeID &id,
                        CanGenericSignature Generics,
                        ArrayRef<SILField> Fields) {
  id.AddPointer(Generics.getPointer());
  for (auto &field : Fields) {
    id.AddPointer(field.getLoweredType().getPointer());
    id.AddBoolean(field.isMutable());
  }
}
<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 */

#pragma once

#include <deque>
#include "future.hh"

/// \addtogroup future-module
/// @{

/// \brief Like \ref future except the result can be waited for by many fibers.
///
/// Represents a value which may not yet be ready. A fiber can wait for the value using
/// the \ref future obtained by calling \ref get_future() or casting to \ref future type.
/// Multiple fibers are allowed to obtain a \ref future for the result using the same
/// instance of \ref shared_future.
///
/// All futures obtained from shared_future should end up in the same state. However,
/// if the value's copy constructor throws, some of the futures may end up in a failed state
/// with an exception thrown from the copy constructor and end up with a state
/// different than other futures.
///
/// The scope of shared_future instance doesn't have to include scopes of the futures
/// obtained from that instance. In that sense the returned futures are independent.
///
/// shared_future can be copied at any time and all copies will resolve with the same value.
///
/// shared_future can be in a disengaged state when it's default-constructed or moved-from.
/// When it's in such a state we say it's invalid and obtaining futures must not be attempted.
///
/// The types in the parameter pack T must all be copy-constructible.
template<typename... T>
class shared_future {
    /// \cond internal
    class shared_state {
        future_state<T...> _future_state;
        std::deque<promise<T...>> _peers;
    public:
        void resolve(future<T...>&& f) noexcept {
            _future_state = f.get_available_state();
            if (_future_state.failed()) {
                for (auto&& p : _peers) {
                    p.set_exception(_future_state.get_exception());
                }
            } else {
                for (auto&& p : _peers) {
                    try {
                        p.set_value(_future_state.get_value());
                    } catch (...) {
                        p.set_exception(std::current_exception());
                    }
                }
            }
            _peers.clear();
        }

        future<T...> get_future() {
            if (!_future_state.available()) {
                promise<T...> p;
                auto f = p.get_future();
                _peers.emplace_back(std::move(p));
                return f;
            } else if (_future_state.failed()) {
                return make_exception_future<T...>(_future_state.get_exception());
            } else {
                try {
                    return make_ready_future<T...>(_future_state.get_value());
                } catch (...) {
                    return make_exception_future<T...>(std::current_exception());
                }
            }
        }
    };
    /// \endcond
    lw_shared_ptr<shared_state> _state;
public:
    /// \brief Forwards the result of future \c f into this shared_future.
    shared_future(future<T...>&& f)
        : _state(make_lw_shared<shared_state>())
    {
        f.then_wrapped([s = _state] (future<T...>&& f) mutable {
            s->resolve(std::move(f));
        });
    }

    shared_future() = default;
    shared_future(const shared_future&) = default;
    shared_future& operator=(const shared_future&) = default;
    shared_future(shared_future&&) = default;
    shared_future& operator=(shared_future&&) = default;

    /// \brief Creates a new \c future which will resolve with the result of this shared_future
    ///
    /// This object must be in a valid state.
    future<T...> get_future() const {
        return _state->get_future();
    }

    /// \brief Equivalent to \ref get_future()
    operator future<T...>() const {
        return get_future();
    }

    /// \brief Returns true if the instance is in valid state
    bool valid() const {
        return bool(_state);
    }
};

/// \brief Like \ref promise except that its counterpart is \ref shared_future instead of \ref future
///
/// When the shared_promise is made ready, every waiter is also made ready.
///
/// Like the shared_future, the types in the parameter pack T must all be copy-constructible.
template <typename... T>
class shared_promise : public enable_shared_from_this<shared_promise<T...>> {
    promise<T...> _promise;
    shared_future<T...> _shared_future;
    static constexpr bool copy_noexcept = future_state<T...>::copy_noexcept;
public:
    shared_promise(const shared_promise&) = delete;
    shared_promise(shared_promise&&) = default;
    shared_promise() : _promise(), _shared_future(_promise.get_future()) {
    }

    future<T...> get_shared_future() {
        return _shared_future.get_future();
    }
    /// \brief Sets the shared_promise's value (as tuple; by copying), same as normal promise
    void set_value(const std::tuple<T...>& result) noexcept(copy_noexcept) {
        _promise.set_value(result);
    }

    /// \brief Sets the shared_promise's value (as tuple; by moving), same as normal promise
    void set_value(std::tuple<T...>&& result) noexcept {
        _promise.set_value(std::move(result));
    }

    /// \brief Sets the shared_promise's value (variadic), same as normal promise
    template <typename... A>
    void set_value(A&&... a) noexcept {
        _promise.set_value(std::forward<A>(a)...);
    }

    /// \brief Marks the shared_promise as failed, same as normal promise
    void set_exception(std::exception_ptr ex) noexcept {
        _promise.set_exception(std::move(ex));
    }

    /// \brief Marks the shared_promise as failed, same as normal promise
    template<typename Exception>
    void set_exception(Exception&& e) noexcept {
        set_exception(make_exception_ptr(std::forward<Exception>(e)));
    }
};

/// @}
<commit_msg>shared_promise: Add move assignment operator<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 */

#pragma once

#include <deque>
#include "future.hh"

/// \addtogroup future-module
/// @{

/// \brief Like \ref future except the result can be waited for by many fibers.
///
/// Represents a value which may not yet be ready. A fiber can wait for the value using
/// the \ref future obtained by calling \ref get_future() or casting to \ref future type.
/// Multiple fibers are allowed to obtain a \ref future for the result using the same
/// instance of \ref shared_future.
///
/// All futures obtained from shared_future should end up in the same state. However,
/// if the value's copy constructor throws, some of the futures may end up in a failed state
/// with an exception thrown from the copy constructor and end up with a state
/// different than other futures.
///
/// The scope of shared_future instance doesn't have to include scopes of the futures
/// obtained from that instance. In that sense the returned futures are independent.
///
/// shared_future can be copied at any time and all copies will resolve with the same value.
///
/// shared_future can be in a disengaged state when it's default-constructed or moved-from.
/// When it's in such a state we say it's invalid and obtaining futures must not be attempted.
///
/// The types in the parameter pack T must all be copy-constructible.
template<typename... T>
class shared_future {
    /// \cond internal
    class shared_state {
        future_state<T...> _future_state;
        std::deque<promise<T...>> _peers;
    public:
        void resolve(future<T...>&& f) noexcept {
            _future_state = f.get_available_state();
            if (_future_state.failed()) {
                for (auto&& p : _peers) {
                    p.set_exception(_future_state.get_exception());
                }
            } else {
                for (auto&& p : _peers) {
                    try {
                        p.set_value(_future_state.get_value());
                    } catch (...) {
                        p.set_exception(std::current_exception());
                    }
                }
            }
            _peers.clear();
        }

        future<T...> get_future() {
            if (!_future_state.available()) {
                promise<T...> p;
                auto f = p.get_future();
                _peers.emplace_back(std::move(p));
                return f;
            } else if (_future_state.failed()) {
                return make_exception_future<T...>(_future_state.get_exception());
            } else {
                try {
                    return make_ready_future<T...>(_future_state.get_value());
                } catch (...) {
                    return make_exception_future<T...>(std::current_exception());
                }
            }
        }
    };
    /// \endcond
    lw_shared_ptr<shared_state> _state;
public:
    /// \brief Forwards the result of future \c f into this shared_future.
    shared_future(future<T...>&& f)
        : _state(make_lw_shared<shared_state>())
    {
        f.then_wrapped([s = _state] (future<T...>&& f) mutable {
            s->resolve(std::move(f));
        });
    }

    shared_future() = default;
    shared_future(const shared_future&) = default;
    shared_future& operator=(const shared_future&) = default;
    shared_future(shared_future&&) = default;
    shared_future& operator=(shared_future&&) = default;

    /// \brief Creates a new \c future which will resolve with the result of this shared_future
    ///
    /// This object must be in a valid state.
    future<T...> get_future() const {
        return _state->get_future();
    }

    /// \brief Equivalent to \ref get_future()
    operator future<T...>() const {
        return get_future();
    }

    /// \brief Returns true if the instance is in valid state
    bool valid() const {
        return bool(_state);
    }
};

/// \brief Like \ref promise except that its counterpart is \ref shared_future instead of \ref future
///
/// When the shared_promise is made ready, every waiter is also made ready.
///
/// Like the shared_future, the types in the parameter pack T must all be copy-constructible.
template <typename... T>
class shared_promise : public enable_shared_from_this<shared_promise<T...>> {
    promise<T...> _promise;
    shared_future<T...> _shared_future;
    static constexpr bool copy_noexcept = future_state<T...>::copy_noexcept;
public:
    shared_promise(const shared_promise&) = delete;
    shared_promise(shared_promise&&) = default;
    shared_promise& operator=(shared_promise&&) = default;
    shared_promise() : _promise(), _shared_future(_promise.get_future()) {
    }

    future<T...> get_shared_future() {
        return _shared_future.get_future();
    }
    /// \brief Sets the shared_promise's value (as tuple; by copying), same as normal promise
    void set_value(const std::tuple<T...>& result) noexcept(copy_noexcept) {
        _promise.set_value(result);
    }

    /// \brief Sets the shared_promise's value (as tuple; by moving), same as normal promise
    void set_value(std::tuple<T...>&& result) noexcept {
        _promise.set_value(std::move(result));
    }

    /// \brief Sets the shared_promise's value (variadic), same as normal promise
    template <typename... A>
    void set_value(A&&... a) noexcept {
        _promise.set_value(std::forward<A>(a)...);
    }

    /// \brief Marks the shared_promise as failed, same as normal promise
    void set_exception(std::exception_ptr ex) noexcept {
        _promise.set_exception(std::move(ex));
    }

    /// \brief Marks the shared_promise as failed, same as normal promise
    template<typename Exception>
    void set_exception(Exception&& e) noexcept {
        set_exception(make_exception_ptr(std::forward<Exception>(e)));
    }
};

/// @}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016 DeepCortex GmbH <legal@eventql.io>
 * Authors:
 *   - Paul Asmuth <paul@eventql.io>
 *   - Christian Parpart <trapni@dawanda.com>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <eventql/sql/result_cursor.h>
#include <eventql/sql/expressions/table_expression.h>

#include "eventql/eventql.h"

namespace csql {

ResultCursor::ResultCursor() :
    started_(false) {}

ResultCursor::ResultCursor(
    ScopedPtr<TableExpression> table_expression) :
    table_expression_(std::move(table_expression)),
    started_(false) {}

bool ResultCursor::next(SValue* row) {
  if (!table_expression_) {
    return false;
  }

  if (!started_) {
    auto rc = table_expression_->execute();
    if (!rc.isSuccess()) {
      RAISE(kRuntimeError, rc.getMessage());
    }

    started_ = true;
  }

  return table_expression_->next(row, table_expression_->getColumnCount());
}

size_t ResultCursor::getColumnCount() const {
  return table_expression_->getColumnCount();
}

SType ResultCursor::getColumnType(size_t idx) const {
  return table_expression_->getColumnType(idx);
}

} // namespace csql

<commit_msg>ResultCursor::getColumnCount for empty results<commit_after>/**
 * Copyright (c) 2016 DeepCortex GmbH <legal@eventql.io>
 * Authors:
 *   - Paul Asmuth <paul@eventql.io>
 *   - Christian Parpart <trapni@dawanda.com>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <eventql/sql/result_cursor.h>
#include <eventql/sql/expressions/table_expression.h>

#include "eventql/eventql.h"

namespace csql {

ResultCursor::ResultCursor() :
    started_(false) {}

ResultCursor::ResultCursor(
    ScopedPtr<TableExpression> table_expression) :
    table_expression_(std::move(table_expression)),
    started_(false) {}

bool ResultCursor::next(SValue* row) {
  if (!table_expression_) {
    return false;
  }

  if (!started_) {
    auto rc = table_expression_->execute();
    if (!rc.isSuccess()) {
      RAISE(kRuntimeError, rc.getMessage());
    }

    started_ = true;
  }

  return table_expression_->next(row, table_expression_->getColumnCount());
}

size_t ResultCursor::getColumnCount() const {
  if (!table_expression_) {
    return 0;
  }

  return table_expression_->getColumnCount();
}

SType ResultCursor::getColumnType(size_t idx) const {
  return table_expression_->getColumnType(idx);
}

} // namespace csql

<|endoftext|>


<commit_before>#include <stdlib.h>
#include <unistd.h>

#define XLOG_MIN_LOG_LVL 3

#include "xlogger.h"
#include "testing_suite.h"

using namespace TOOLS;
using namespace TOOLS::UNIT_TEST;
using namespace std;

#define LOGID "system"

#ifndef GENERATE_HEADER
void loglvl_action() {
  INFO << "Loglvl action successful!";
}
#endif

START_SUITE(XLoggerToolsTestSuite) {
      REG_TEST(simple)
      REG_TEST(loglvl_action)
    }

    XLogger* xlog;
    MemoryBackend* mb;

    virtual void setup() {
      xlog = new XLogger(LOGID);
      //xlog->add_backend(new ConsoleBackend(LOGID));
      mb = new MemoryBackend(LOGID);
      xlog->set_min_loglvl(1);
      xlog->add_backend(mb);
    }

    virtual void tear_down() {
      delete xlog;
    }

    MAKE_TEST(simple) {
      CHECK(mb->log_msgs.size() == 1);
      int tmp = 123;
      DEBUG << "starting logger testing!";
      INFO << "more info logging, let's log an integer: " << tmp;
      WARN << "oh oh, this is a warning - this could end bad!";

      CHECK(mb->log_msgs.size() == 4);
    }

    MAKE_TEST(loglvl_action) {
      INFO << "STARTING";
      xlog->set_loglvl_action(10, loglvl_action);
      ERROR << "ERRRRORRRRR, should trigger action";
      CHECK(mb->log_msgs.size() == 4);
    }

    MAKE_TEST(endline) {
      INFO << "yiha" << std::endl;
      CHECK(true);
    }

END_SUITE()
<commit_msg>unit test for xlogger endline added<commit_after>#include <stdlib.h>
#include <unistd.h>

#define XLOG_MIN_LOG_LVL 3

#include "xlogger.h"
#include "testing_suite.h"

using namespace TOOLS;
using namespace TOOLS::UNIT_TEST;
using namespace std;

#define LOGID "system"

#ifndef GENERATE_HEADER
void loglvl_action() {
  INFO << "Loglvl action successful!";
}
#endif

START_SUITE(XLoggerToolsTestSuite) {
      REG_TEST(simple)
      REG_TEST(loglvl_action)
      REG_TEST(endline)
    }

    XLogger* xlog;
    MemoryBackend* mb;

    virtual void setup() {
      xlog = new XLogger(LOGID);
      //xlog->add_backend(new ConsoleBackend(LOGID));
      mb = new MemoryBackend(LOGID);
      xlog->set_min_loglvl(1);
      xlog->add_backend(mb);
    }

    virtual void tear_down() {
      delete xlog;
    }

    MAKE_TEST(simple) {
      CHECK(mb->log_msgs.size() == 1);
      int tmp = 123;
      DEBUG << "starting logger testing!";
      INFO << "more info logging, let's log an integer: " << tmp;
      WARN << "oh oh, this is a warning - this could end bad!";

      CHECK(mb->log_msgs.size() == 4);
    }

    MAKE_TEST(loglvl_action) {
      INFO << "STARTING";
      xlog->set_loglvl_action(10, loglvl_action);
      ERROR << "ERRRRORRRRR, should trigger action";
      CHECK(mb->log_msgs.size() == 4);
    }

    MAKE_TEST(endline) {
      //INFO << "yiha" << std::endl;
      CHECK(false);
    }

END_SUITE()
<|endoftext|>


<commit_before>#include <complex>
#include <vector>
#include <fstream>
// boost/geometry/algorithms/detail/overlay/handle_colocations.hpp:198:10:
// error: no member named 'cout' in namespace 'std'
#include <iostream>

#include "base/base.h"
#include "boost/rational.hpp"
#include <boost/geometry.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/sym_difference.hpp>
// #include <boost/geometry/algorithms/equals.hpp>
// #include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/algorithms/union.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/multiprecision/gmp.hpp>
#include "polygon.h"
#include "problem.h"
#include "solution.h"

DEFINE_string(problem, "", "input problem file");
DEFINE_string(solution, "", "input solution file");
DEFINE_bool(show_figure, false, "show rich output");

namespace bg = boost::geometry;

using gPoint = bg::model::d2::point_xy<Q>;
using ccwRing = bg::model::ring<gPoint, false, false>;
using ccwPolygon = bg::model::polygon<gPoint, false, false>;
using ccwMultiPolygon = bg::model::multi_polygon<ccwPolygon>;
using namespace std;

namespace boost {
// For bg::convert across coordinate systems from gPoint to RealPoint
template <>
double numeric_cast<double>(const Q& x) {
  return x.convert_to<double>();
}
}

gPoint rotCCW(const gPoint& p) { return gPoint(-p.y(), p.x()); }

Q cross(const gPoint& lhs, const gPoint& rhs) {
  return lhs.x() * rhs.y() - lhs.y() * rhs.x();
}

// namespace boost {
// namespace multiprecision {
// // False sqrt for bg::equals
// // boost/geometry/algorithms/detail/equals/collect_vectors.hpp:138:48
// // that uses sqrt to compare vector directions with unit vectors.
// Q sqrt(const Q& q) {
//   long double x = sqrtl(q.convert_to<long double>());
//   long double i;
//   long double f = modfl(x, &i);
//   if (f == 0) return Q((long long)i);
//   int exp;
//   x = frexpl(x, &exp);
//   const int kBias = 20;
//   x = ldexpl(x, exp + 20);
//   return Q((long long)roundl(x), 1ll << kBias);
// }
// }
// }

template <typename T>
void normalize_pair(std::pair<T, T>* p) {
  if (p->second < p->first) std::swap(p->first, p->second);
}

int main(int argc, char** argv) {
  ParseCommandLineFlags(&argc, &argv);

  VLOG(2) << "Loading file " << FLAGS_problem;
  Problem problem;
  std::ifstream problem_ifs(FLAGS_problem);
  CHECK(ReadProblem(problem_ifs, &problem)) << "Failed to load file "
                                            << FLAGS_problem;
  VLOG(2) << "Loading file " << FLAGS_solution;
  Solution solution;
  std::ifstream solution_ifs(FLAGS_solution);
  CHECK(ReadSolution(solution_ifs, &solution)) << "Failed to load file "
                                               << FLAGS_solution;
  VLOG(2) << "Files loaded";

  // edge (normalized pair of vertex ids) to facet ids
  map<pair<int, int>, set<int>> edge_to_facet;
  for (int i = 0; i < solution.facets.size(); ++i) {
    for (int j = 0; j < solution.facets[i].size() - 1; ++j) {
      pair<int, int> edge(solution.facets[i][j], solution.facets[i][j + 1]);
      normalize_pair(&edge);
      edge_to_facet[edge].insert(i);
    }
  }
  for (const auto& it : edge_to_facet) {
    const auto& edge = it.first;
    const auto& adj_facets = it.second;
    if (adj_facets.size() > 2) {
      LOG(FATAL) << "Edge[" << edge.first << "," << edge.second
                 << "] is shared by more than 2 facets ("
                 << strings::JoinInts(adj_facets, ",") << ")";
    }
  }

  // Verify src facets congruence vs dst
  vector<ccwRing> dst_rings;
  for (const auto& facet : solution.facets) {
    LOG_IF(FATAL, facet.size() < 3) << "Facet has less than 3 vertices ("
                                    << strings::JoinInts(facet, ",") << ")";
    ccwRing src_ring, dst_ring;
    for (const auto& i : facet) {
      bg::append(src_ring,
                 gPoint(solution.src_verts[i].x, solution.src_verts[i].y));
      bg::append(dst_ring,
                 gPoint(solution.dst_verts[i].x, solution.dst_verts[i].y));
    }
    bool mirror;
    bool error = false;
    for (int i = 1; i < src_ring.size() - 1; ++i) {
      gPoint s1 = src_ring[i];
      gPoint s2 = src_ring[i + 1];
      bg::subtract_point(s1, src_ring[0]);
      bg::subtract_point(s2, src_ring[0]);
      Q gs1 = bg::dot_product(s1, s2);
      Q gs2 = bg::dot_product(rotCCW(s1), s2);
      gPoint d1 = dst_ring[i];
      gPoint d2 = dst_ring[i + 1];
      bg::subtract_point(d1, dst_ring[0]);
      bg::subtract_point(d2, dst_ring[0]);
      Q gd1 = bg::dot_product(d1, d2);
      Q gd2 = bg::dot_product(rotCCW(d1), d2);
      // find if flipped or not with the first angle
      if (i == 1) mirror = gs2.sign() != gd2.sign();
      bool congruent = gs1 == gd1 && gs2 == (mirror ? -gd2 : gd2);
      LOG_IF(FATAL, !congruent)
          << "Facet is not congruent between source and destination: "
          << bg::wkt(src_ring) << " vs " << bg::wkt(dst_ring);
    }

    bg::correct(dst_ring);
    dst_rings.push_back(std::move(dst_ring));
  }

  // Verify dst facets shape problem silhouette
  ccwMultiPolygon dst_mpoly;
  for (const auto& ring : dst_rings) {
    ccwMultiPolygon tmp;
    bg::union_(dst_mpoly, ring, tmp);
    dst_mpoly.swap(tmp);
  }
  ccwPolygon silhouette;
  for (const auto& poly : problem.polygons) {
    ccwRing ring;
    for (const auto& v : poly) {
      bg::append(ring, gPoint(v.x, v.y));
    }
    ccwMultiPolygon out;
    if (bg::area(ring) > 0) {
      bg::union_(silhouette, ring, out);
    } else {
      bg::correct(ring);
      bg::difference(silhouette, ring, out);
    }
    if (out.size() == 0) {
      LOG(ERROR) << "Found holes before positive silhouette.";
    } else {
      LOG_IF(ERROR, out.size() > 1)
          << "Problem silhouette has disjoint polygons: " << bg::wkt(out);
      silhouette = out[0];
    }
  }
  LOG_IF(ERROR, !bg::is_valid(silhouette)) << "Problem silhouette is invalid."
                                           << bg::wkt(silhouette);
  auto silhouette_area = bg::area(silhouette);
  LOG_IF(ERROR, silhouette_area < 0 || 1 < silhouette_area)
      << "Silhouette doesn't have area between [0,1]: " << silhouette_area;
  ccwMultiPolygon diff;
  bg::sym_difference(silhouette, dst_mpoly, diff);
  if (!bg::area(diff).is_zero()) {
    LOG(WARNING) << "Destionation silhouette doesn't match.";
    ccwMultiPolygon diff1, diff2;
    bg::difference(silhouette, dst_mpoly, diff1);
    bg::difference(dst_mpoly, silhouette, diff2);
    if (FLAGS_show_figure) {
      using RealPoint = bg::model::d2::point_xy<double>;
      bg::model::multi_polygon<bg::model::polygon<RealPoint, false, false>>
          real_diff1, real_diff2;
      bg::convert(diff1, real_diff1);
      bg::convert(diff2, real_diff2);
      bg::model::box<RealPoint> rect = {{0, 0}, {1, 1}};
      bg::svg_mapper<RealPoint> mapper(
          std::cout, 1000, 1000,
          R"(width="400px" height="400px" viewBox="0 0 1000 1000")");
      mapper.add(rect);
      mapper.add(real_diff1);
      mapper.add(real_diff2);
      mapper.map(rect, "fill:none;stroke:blue;stroke-width:5");
      mapper.map(real_diff1, "fill:turquoise");
      mapper.map(real_diff2, "fill:tomato");
    }
    LOG(WARNING) << "Diff1: " << bg::wkt(diff1);
    LOG(WARNING) << "Diff2: " << bg::wkt(diff2);
  }

  // TODO: Calculate score?

  LOG(INFO) << "Validated";

  return 0;
}
<commit_msg>dump facet id<commit_after>#include <complex>
#include <vector>
#include <fstream>
// boost/geometry/algorithms/detail/overlay/handle_colocations.hpp:198:10:
// error: no member named 'cout' in namespace 'std'
#include <iostream>

#include "base/base.h"
#include "boost/rational.hpp"
#include <boost/geometry.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/sym_difference.hpp>
// #include <boost/geometry/algorithms/equals.hpp>
// #include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/algorithms/union.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/multiprecision/gmp.hpp>
#include "polygon.h"
#include "problem.h"
#include "solution.h"

DEFINE_string(problem, "", "input problem file");
DEFINE_string(solution, "", "input solution file");
DEFINE_bool(show_figure, false, "show rich output");

namespace bg = boost::geometry;

using gPoint = bg::model::d2::point_xy<Q>;
using ccwRing = bg::model::ring<gPoint, false, false>;
using ccwPolygon = bg::model::polygon<gPoint, false, false>;
using ccwMultiPolygon = bg::model::multi_polygon<ccwPolygon>;
using namespace std;

namespace boost {
// For bg::convert across coordinate systems from gPoint to RealPoint
template <>
double numeric_cast<double>(const Q& x) {
  return x.convert_to<double>();
}
}

gPoint rotCCW(const gPoint& p) { return gPoint(-p.y(), p.x()); }

Q cross(const gPoint& lhs, const gPoint& rhs) {
  return lhs.x() * rhs.y() - lhs.y() * rhs.x();
}

// namespace boost {
// namespace multiprecision {
// // False sqrt for bg::equals
// // boost/geometry/algorithms/detail/equals/collect_vectors.hpp:138:48
// // that uses sqrt to compare vector directions with unit vectors.
// Q sqrt(const Q& q) {
//   long double x = sqrtl(q.convert_to<long double>());
//   long double i;
//   long double f = modfl(x, &i);
//   if (f == 0) return Q((long long)i);
//   int exp;
//   x = frexpl(x, &exp);
//   const int kBias = 20;
//   x = ldexpl(x, exp + 20);
//   return Q((long long)roundl(x), 1ll << kBias);
// }
// }
// }

template <typename T>
void normalize_pair(std::pair<T, T>* p) {
  if (p->second < p->first) std::swap(p->first, p->second);
}

int main(int argc, char** argv) {
  ParseCommandLineFlags(&argc, &argv);

  VLOG(2) << "Loading file " << FLAGS_problem;
  Problem problem;
  std::ifstream problem_ifs(FLAGS_problem);
  CHECK(ReadProblem(problem_ifs, &problem)) << "Failed to load file "
                                            << FLAGS_problem;
  VLOG(2) << "Loading file " << FLAGS_solution;
  Solution solution;
  std::ifstream solution_ifs(FLAGS_solution);
  CHECK(ReadSolution(solution_ifs, &solution)) << "Failed to load file "
                                               << FLAGS_solution;
  VLOG(2) << "Files loaded";

  // edge (normalized pair of vertex ids) to facet ids
  map<pair<int, int>, set<int>> edge_to_facet;
  for (int i = 0; i < solution.facets.size(); ++i) {
    for (int j = 0; j < solution.facets[i].size() - 1; ++j) {
      pair<int, int> edge(solution.facets[i][j], solution.facets[i][j + 1]);
      normalize_pair(&edge);
      edge_to_facet[edge].insert(i);
    }
  }
  for (const auto& it : edge_to_facet) {
    const auto& edge = it.first;
    const auto& adj_facets = it.second;
    if (adj_facets.size() > 2) {
      LOG(FATAL) << "Edge[" << edge.first << "," << edge.second
                 << "] is shared by more than 2 facets ("
                 << strings::JoinInts(adj_facets, ",") << ")";
    }
  }

  // Verify src facets congruence vs dst
  vector<ccwRing> dst_rings;
  for (int facet_id = 0; facet_id < solution.facets.size(); ++facet_id) {
    const auto& facet = solution.facets[facet_id];
    LOG_IF(FATAL, facet.size() < 3) << "Facet[" << facet_id << "]("
                                    << strings::JoinInts(facet, " ")
                                    << ") has less than 3 vertices";
    ccwRing src_ring, dst_ring;
    for (const auto& i : facet) {
      bg::append(src_ring,
                 gPoint(solution.src_verts[i].x, solution.src_verts[i].y));
      bg::append(dst_ring,
                 gPoint(solution.dst_verts[i].x, solution.dst_verts[i].y));
    }
    bool mirror;
    bool error = false;
    for (int i = 1; i < src_ring.size() - 1; ++i) {
      gPoint s1 = src_ring[i];
      gPoint s2 = src_ring[i + 1];
      bg::subtract_point(s1, src_ring[0]);
      bg::subtract_point(s2, src_ring[0]);
      Q gs1 = bg::dot_product(s1, s2);
      Q gs2 = bg::dot_product(rotCCW(s1), s2);
      gPoint d1 = dst_ring[i];
      gPoint d2 = dst_ring[i + 1];
      bg::subtract_point(d1, dst_ring[0]);
      bg::subtract_point(d2, dst_ring[0]);
      Q gd1 = bg::dot_product(d1, d2);
      Q gd2 = bg::dot_product(rotCCW(d1), d2);
      // find if flipped or not with the first angle
      if (i == 1) mirror = gs2.sign() != gd2.sign();
      bool congruent = gs1 == gd1 && gs2 == (mirror ? -gd2 : gd2);
      LOG_IF(FATAL, !congruent)
          << "Facet[" << facet_id << "](" << strings::JoinInts(facet, " ")
          << ") is not congruent between source and destination: "
          << bg::wkt(src_ring) << " vs " << bg::wkt(dst_ring);
    }

    bg::correct(dst_ring);
    dst_rings.push_back(std::move(dst_ring));
  }

  // Verify dst facets shape problem silhouette
  ccwMultiPolygon dst_mpoly;
  for (const auto& ring : dst_rings) {
    ccwMultiPolygon tmp;
    bg::union_(dst_mpoly, ring, tmp);
    dst_mpoly.swap(tmp);
  }
  ccwPolygon silhouette;
  for (const auto& poly : problem.polygons) {
    ccwRing ring;
    for (const auto& v : poly) {
      bg::append(ring, gPoint(v.x, v.y));
    }
    ccwMultiPolygon out;
    if (bg::area(ring) > 0) {
      bg::union_(silhouette, ring, out);
    } else {
      bg::correct(ring);
      bg::difference(silhouette, ring, out);
    }
    if (out.size() == 0) {
      LOG(ERROR) << "Found holes before positive silhouette.";
    } else {
      LOG_IF(ERROR, out.size() > 1)
          << "Problem silhouette has disjoint polygons: " << bg::wkt(out);
      silhouette = out[0];
    }
  }
  LOG_IF(ERROR, !bg::is_valid(silhouette)) << "Problem silhouette is invalid."
                                           << bg::wkt(silhouette);
  auto silhouette_area = bg::area(silhouette);
  LOG_IF(ERROR, silhouette_area < 0 || 1 < silhouette_area)
      << "Silhouette doesn't have area between [0,1]: " << silhouette_area;
  ccwMultiPolygon diff;
  bg::sym_difference(silhouette, dst_mpoly, diff);
  if (!bg::area(diff).is_zero()) {
    LOG(WARNING) << "Destionation silhouette doesn't match.";
    ccwMultiPolygon diff1, diff2;
    bg::difference(silhouette, dst_mpoly, diff1);
    bg::difference(dst_mpoly, silhouette, diff2);
    if (FLAGS_show_figure) {
      using RealPoint = bg::model::d2::point_xy<double>;
      bg::model::multi_polygon<bg::model::polygon<RealPoint, false, false>>
          real_diff1, real_diff2;
      bg::convert(diff1, real_diff1);
      bg::convert(diff2, real_diff2);
      bg::model::box<RealPoint> rect = {{0, 0}, {1, 1}};
      bg::svg_mapper<RealPoint> mapper(
          std::cout, 1000, 1000,
          R"(width="400px" height="400px" viewBox="0 0 1000 1000")");
      mapper.add(rect);
      mapper.add(real_diff1);
      mapper.add(real_diff2);
      mapper.map(rect, "fill:none;stroke:blue;stroke-width:5");
      mapper.map(real_diff1, "fill:turquoise");
      mapper.map(real_diff2, "fill:tomato");
    }
    LOG(WARNING) << "Diff1: " << bg::wkt(diff1);
    LOG(WARNING) << "Diff2: " << bg::wkt(diff2);
  }

  // TODO: Calculate score?

  LOG(INFO) << "Validated";

  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEML2P_MORTAR_ASSEMBLER_HPP
#define MFEML2P_MORTAR_ASSEMBLER_HPP

#include "../fem.hpp"
#include "mortarintegrator.hpp"
#include <memory>

namespace mfem
{
/*!
 * @brief This class implements the serial variational transfer between finite
 * element spaces. Variational transfer has been shown to have better
 * approximation properties than standard interpolation. This facilities can be
 * used for supporting applications wich require the handling of non matching
 * meshes. For instance: General multi-physics problems, fluid structure
 * interaction, or even visulization of average quanties within subvolumes
 * This algorithm allows to perform quadrature in the intersection of elements
 * of two separate and unrelated meshes. It generates quadrature rules in
 * the intersection which allows us to integrate-with to machine precision using
 * the mfem::MortarIntegrator interface. See https://doi.org/10.1137/15M1008361
 * for and in-depth explanation. At this time curved elements are not supported.
 */
class MortarAssembler
{
public:
   /*!
    * @brief constructs the object with source and destination spaces
    * @param source the source space from where we want to transfer the discrete
    * field
    * @param destination the source space to where we want to transfer the
    * discrete field
    */
   MortarAssembler(const std::shared_ptr<FiniteElementSpace> &source,
                   const std::shared_ptr<FiniteElementSpace> &destination);

   ~MortarAssembler();

   /*!
    * @brief assembles the coupling matrix B. B : source -> destination If u is a
    * coefficient associated with source and v with destination Then v = M^(-1) *
    * B * u; where M is the mass matrix in destination. Works with
    * L2_FECollection, H1_FECollection and DG_FECollection (experimental with
    * RT_FECollection and ND_FECollection).
    * @param B the assembled coupling operator. B can be passed uninitialized.
    * @return true if there was an intersection and the operator has been
    * assembled. False otherwise.
    */
   bool Assemble(std::shared_ptr<SparseMatrix> &B);

   /*!
    * @brief transfer a function from source to destination. if the transfer is
    * to be performed multiple times use Assemble instead
    * @param src_fun the function associated with the source finite element space
    * @param[out] dest_fun the function associated with the destination finite
    * element space
    * @return true if there was an intersection and the output can be used.
    */
   bool Transfer(GridFunction &src_fun, GridFunction &dest_fun);

   /*!
    * @brief transfer a function from source to destination. It requires that
    * the Init function is called before
    * @param src_fun the function associated with the source finite element space
    * @param[out] dest_fun the function associated with the destination finite
    * element space
    * @return true if the transfer was succesfull, fale otherwise.
    */
   bool Apply(GridFunction &src_fun, GridFunction &dest_fun);

   /*!
    * @brief assembles the various components necessary for the transfer.
    * To before alling the Apply function. Works with
    * L2_FECollection, H1_FECollection and DG_FECollection (experimental with
    * RT_FECollection and ND_FECollection).
    * @return true if there was an intersection and the operator has been
    * assembled. False otherwise.
    */
   bool Init();

   /*!
    * @brief This method must be called before Assemble or Transfer.
    * It will assemble the operator in all intersections found.
    * @param integrator the integrator object
    */
   void AddMortarIntegrator(const std::shared_ptr<MortarIntegrator> &integrator);

   /*!
    * @brief Expose process details with verbose output
    * @param verbose is set to true for verbose output
    */
   void SetVerbose(const bool verbose);

private:
   class Impl;
   std::unique_ptr<Impl> impl_;
};

} // namespace mfem

#endif // MFEML2P_MORTAR_ASSEMBLER_HPP
<commit_msg>Update fem/moonolith/mortarassembler.hpp<commit_after>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEML2P_MORTAR_ASSEMBLER_HPP
#define MFEML2P_MORTAR_ASSEMBLER_HPP

#include "../fem.hpp"
#include "mortarintegrator.hpp"
#include <memory>

namespace mfem
{
/*!
 * @brief This class implements the serial variational transfer between finite
 * element spaces. Variational transfer has been shown to have better
 * approximation properties than standard interpolation. This facilities can be
 * used for supporting applications wich require the handling of non matching
 * meshes. For instance: General multi-physics problems, fluid structure
 * interaction, or even visulization of average quanties within subvolumes
 * This algorithm allows to perform quadrature in the intersection of elements
 * of two separate and unrelated meshes. It generates quadrature rules in
 * the intersection which allows us to integrate-with to machine precision using
 * the mfem::MortarIntegrator interface. See https://doi.org/10.1137/15M1008361
 * for and in-depth explanation. At this time curved elements are not supported.
 */
class MortarAssembler
{
public:
   /*!
    * @brief constructs the object with source and destination spaces
    * @param source the source space from where we want to transfer the discrete
    * field
    * @param destination the source space to where we want to transfer the
    * discrete field
    */
   MortarAssembler(const std::shared_ptr<FiniteElementSpace> &source,
                   const std::shared_ptr<FiniteElementSpace> &destination);

   ~MortarAssembler();

   /*!
    * @brief assembles the coupling matrix B. B : source -> destination If u is a
    * coefficient associated with source and v with destination Then v = M^(-1) *
    * B * u; where M is the mass matrix in destination. Works with
    * L2_FECollection, H1_FECollection and DG_FECollection (experimental with
    * RT_FECollection and ND_FECollection).
    * @param B the assembled coupling operator. B can be passed uninitialized.
    * @return true if there was an intersection and the operator has been
    * assembled. False otherwise.
    */
   bool Assemble(std::shared_ptr<SparseMatrix> &B);

   /*!
    * @brief transfer a function from source to destination. if the transfer is
    * to be performed multiple times use Assemble instead
    * @param src_fun the function associated with the source finite element space
    * @param[out] dest_fun the function associated with the destination finite
    * element space
    * @return true if there was an intersection and the output can be used.
    */
   bool Transfer(const GridFunction &src_fun, GridFunction &dest_fun);

   /*!
    * @brief transfer a function from source to destination. It requires that
    * the Init function is called before
    * @param src_fun the function associated with the source finite element space
    * @param[out] dest_fun the function associated with the destination finite
    * element space
    * @return true if the transfer was succesfull, fale otherwise.
    */
   bool Apply(GridFunction &src_fun, GridFunction &dest_fun);

   /*!
    * @brief assembles the various components necessary for the transfer.
    * To before alling the Apply function. Works with
    * L2_FECollection, H1_FECollection and DG_FECollection (experimental with
    * RT_FECollection and ND_FECollection).
    * @return true if there was an intersection and the operator has been
    * assembled. False otherwise.
    */
   bool Init();

   /*!
    * @brief This method must be called before Assemble or Transfer.
    * It will assemble the operator in all intersections found.
    * @param integrator the integrator object
    */
   void AddMortarIntegrator(const std::shared_ptr<MortarIntegrator> &integrator);

   /*!
    * @brief Expose process details with verbose output
    * @param verbose is set to true for verbose output
    */
   void SetVerbose(const bool verbose);

private:
   class Impl;
   std::unique_ptr<Impl> impl_;
};

} // namespace mfem

#endif // MFEML2P_MORTAR_ASSEMBLER_HPP
<|endoftext|>


<commit_before>#ifndef VARIANT_HPP
#define VARIANT_HPP

#include <type_traits>
#include <memory>
#include <cassert>

template<class ... T> class variant;

namespace impl {
  template<std::size_t start, class ... T>
  struct select;

  template<std::size_t start, class H, class ... T>
  struct select<start, H, T...> : select<start + 1, T...> {

    using select<start + 1, T...>::index;
    static constexpr std::size_t index(const H* ) { return start; }

    using select<start + 1, T...>::cast;
    static constexpr const H& cast(const H& value) { return value; }
    static constexpr H&& cast(H&& value) { return std::move(value); }

  };

  template<std::size_t start> struct select<start> {
    static void index();
    static void cast();
  };

  template<class Variant, class Self, class Signature>
  struct dispatch;

  template<class ... T, class Self, class Visitor, class Ret, class ... Args>
  struct dispatch<variant<T...>, Self, Ret (Visitor, Args...) > {

    template<class U>
    static Ret call_thunk(Self& self, Visitor&& visitor, Args&& ... args) {
      return std::forward<Visitor>(visitor)(self.template get<U>(), std::forward<Args>(args)...);
    }

    using thunk_type = Ret (*)(Self& self, Visitor&& visitor, Args&& ... args);
    static constexpr thunk_type table[] = { call_thunk<T>... };
  };

  template<class ... T, class Self, class Visitor,  class Ret, class ... Args>
  constexpr typename dispatch<variant<T...>, Self, Ret (Visitor, Args...) >::thunk_type
  dispatch<variant<T...>, Self, Ret (Visitor, Args...) >::table[];

}

template<class ... T>
class variant {

  using storage_type = typename std::aligned_union<0, T...>::type;
  storage_type storage;

  using index_type = std::size_t;
  index_type index;

  using select_type = impl::select<0, T...>;

  template<class U>
  void construct(U&& value) {
    new (&storage) typename std::decay<U>::type(std::forward<U>(value));
  }

  struct copy_construct {
    template<class U>
    void operator()(U& self, const variant& other) const {
      new (&self) U(other.template get<U>());
    }
  };

  struct copy {
    template<class U>
    void operator()(U& self, const variant& other) const {
      self = other.template get<U>();
    }
  };

  struct move {
    template<class U>
    void operator()(U& self, variant&& other) const {
      self = std::move(other.template get<U>());
    }
  };

  struct move_construct {
    template<class U>
    void operator()(U& self, variant&& other) const {
      new (&self) U(std::move(other.template get<U>()));
    }
  };

  struct destruct {
    template<class U>
    void operator()(U& self) const {
      self.~U();
    }
  };

public:
  std::size_t type() const { return index; }

  struct bad_cast : std::runtime_error {
    bad_cast() : std::runtime_error("bad_cast") { }
  };

  template<class U, index_type R = select_type::index( ((typename std::decay<U>::type*)0) ) >
  static constexpr index_type type_index() { return R; }

  template<class U, index_type R = type_index<U>() >
  U& cast() {
    U& res = reinterpret_cast<U&>(storage);
    if( R != index ) throw bad_cast();
    return res;
  }

  template<class U, index_type R = type_index<U>() >
  const U& cast() const {
    const U& res = reinterpret_cast<const U&>(storage);
    if(R != index ) {
      throw std::runtime_error("bad cast");
    }
    return res;
  }

  template<class U, index_type R = type_index<U>()>
  U& get() noexcept {
    U& res = reinterpret_cast<U&>(storage);
    assert(R == index);
    return res;
  }

  template<class U, index_type R = type_index<U>() >
  const U& get() const noexcept {
    const U& res = reinterpret_cast<const U&>(storage);
    assert(R == index);
    return res;
  }

  template<class U, index_type R = type_index<U>() >
  bool is() const noexcept {
    return R == index;
  }

  variant(const variant& other) noexcept
    : index(other.index) {
    apply( copy_construct(), other );
  }

  variant(variant&& other) noexcept
    : index(other.index) {
    apply( move_construct(), std::move(other) );
  }

  ~variant() noexcept {
    apply( destruct() );
  }

  variant& operator=(const variant& other) noexcept {
    if(type() == other.type()) {
      apply( copy(), other );
    } else {
      apply( destruct() );
      apply( copy_construct(), other );
    }

    return *this;
  }

  variant& operator=(variant&& other)  noexcept{
    if(type() == other.type()) {
      apply( move(), std::move(other) );
    } else {
      apply( destruct() );
      apply( move_construct(), std::move(other) );
    }

    return *this;
  }

  template<class U, index_type R = type_index<U>() >
  variant(U&& value) noexcept
    : index( R ) {
    construct( select_type::cast( std::forward<U>(value)) );
  }

  template<class Visitor, class ... Args>
  void apply(Visitor&& visitor, Args&& ... args) {

    impl::dispatch<variant, variant, void (Visitor, Args...)>::table[index]
      (*this, std::forward<Visitor>(visitor), std::forward<Args>(args)...);

  }

  template<class Visitor, class ... Args>
  void apply(Visitor&& visitor, Args&& ... args) const {

    impl::dispatch<variant, const variant, void (Visitor, Args...)>::table[index]
      (*this, std::forward<Visitor>(visitor), std::forward<Args>(args)...);

  }

  template<class Visitor, class ... Args>
  variant map(Visitor&& visitor, Args&& ... args) const {

    return impl::dispatch<variant, const variant, variant(Visitor, Args...) >::table[index]
      (*this, std::forward<Visitor>(visitor), std::forward<Args>(args)...);
  }

};

#endif
<commit_msg>fix compilation<commit_after>#ifndef VARIANT_HPP
#define VARIANT_HPP

#include <type_traits>
#include <memory>
#include <cassert>
#include <stdexcept>

template<class ... T> class variant;

namespace impl {
  template<std::size_t start, class ... T>
  struct select;

  template<std::size_t start, class H, class ... T>
  struct select<start, H, T...> : select<start + 1, T...> {

    using select<start + 1, T...>::index;
    static constexpr std::size_t index(const H* ) { return start; }

    using select<start + 1, T...>::cast;
    static constexpr const H& cast(const H& value) { return value; }
    static constexpr H&& cast(H&& value) { return std::move(value); }

  };

  template<std::size_t start> struct select<start> {
    static void index();
    static void cast();
  };

  template<class Variant, class Self, class Signature>
  struct dispatch;

  template<class ... T, class Self, class Visitor, class Ret, class ... Args>
  struct dispatch<variant<T...>, Self, Ret (Visitor, Args...) > {

    template<class U>
    static Ret call_thunk(Self& self, Visitor&& visitor, Args&& ... args) {
      return std::forward<Visitor>(visitor)(self.template get<U>(), std::forward<Args>(args)...);
    }

    using thunk_type = Ret (*)(Self& self, Visitor&& visitor, Args&& ... args);
    static constexpr thunk_type table[] = { call_thunk<T>... };
  };

  template<class ... T, class Self, class Visitor,  class Ret, class ... Args>
  constexpr typename dispatch<variant<T...>, Self, Ret (Visitor, Args...) >::thunk_type
  dispatch<variant<T...>, Self, Ret (Visitor, Args...) >::table[];

}

template<class ... T>
class variant {

  using storage_type = typename std::aligned_union<0, T...>::type;
  storage_type storage;

  using index_type = std::size_t;
  index_type index;

  using select_type = impl::select<0, T...>;

  template<class U>
  void construct(U&& value) {
    new (&storage) typename std::decay<U>::type(std::forward<U>(value));
  }

  struct copy_construct {
    template<class U>
    void operator()(U& self, const variant& other) const {
      new (&self) U(other.template get<U>());
    }
  };

  struct copy {
    template<class U>
    void operator()(U& self, const variant& other) const {
      self = other.template get<U>();
    }
  };

  struct move {
    template<class U>
    void operator()(U& self, variant&& other) const {
      self = std::move(other.template get<U>());
    }
  };

  struct move_construct {
    template<class U>
    void operator()(U& self, variant&& other) const {
      new (&self) U(std::move(other.template get<U>()));
    }
  };

  struct destruct {
    template<class U>
    void operator()(U& self) const {
      self.~U();
    }
  };

public:
  std::size_t type() const { return index; }

  struct bad_cast : std::runtime_error {
    bad_cast() : std::runtime_error("bad_cast") { }
  };

  template<class U, index_type R = select_type::index( ((typename std::decay<U>::type*)0) ) >
  static constexpr index_type type_index() { return R; }

  template<class U, index_type R = type_index<U>() >
  U& cast() {
    U& res = reinterpret_cast<U&>(storage);
    if( R != index ) throw bad_cast();
    return res;
  }

  template<class U, index_type R = type_index<U>() >
  const U& cast() const {
    const U& res = reinterpret_cast<const U&>(storage);
    if(R != index ) {
      throw std::runtime_error("bad cast");
    }
    return res;
  }

  template<class U, index_type R = type_index<U>()>
  U& get() noexcept {
    U& res = reinterpret_cast<U&>(storage);
    assert(R == index);
    return res;
  }

  template<class U, index_type R = type_index<U>() >
  const U& get() const noexcept {
    const U& res = reinterpret_cast<const U&>(storage);
    assert(R == index);
    return res;
  }

  template<class U, index_type R = type_index<U>() >
  bool is() const noexcept {
    return R == index;
  }

  variant(const variant& other) noexcept
    : index(other.index) {
    apply( copy_construct(), other );
  }

  variant(variant&& other) noexcept
    : index(other.index) {
    apply( move_construct(), std::move(other) );
  }

  ~variant() noexcept {
    apply( destruct() );
  }

  variant& operator=(const variant& other) noexcept {
    if(type() == other.type()) {
      apply( copy(), other );
    } else {
      apply( destruct() );
      apply( copy_construct(), other );
    }

    return *this;
  }

  variant& operator=(variant&& other)  noexcept{
    if(type() == other.type()) {
      apply( move(), std::move(other) );
    } else {
      apply( destruct() );
      apply( move_construct(), std::move(other) );
    }

    return *this;
  }

  template<class U, index_type R = type_index<U>() >
  variant(U&& value) noexcept
    : index( R ) {
    construct( select_type::cast( std::forward<U>(value)) );
  }

  template<class Visitor, class ... Args>
  void apply(Visitor&& visitor, Args&& ... args) {

    impl::dispatch<variant, variant, void (Visitor, Args...)>::table[index]
      (*this, std::forward<Visitor>(visitor), std::forward<Args>(args)...);

  }

  template<class Visitor, class ... Args>
  void apply(Visitor&& visitor, Args&& ... args) const {

    impl::dispatch<variant, const variant, void (Visitor, Args...)>::table[index]
      (*this, std::forward<Visitor>(visitor), std::forward<Args>(args)...);

  }

  template<class Visitor, class ... Args>
  variant map(Visitor&& visitor, Args&& ... args) const {

    return impl::dispatch<variant, const variant, variant(Visitor, Args...) >::table[index]
      (*this, std::forward<Visitor>(visitor), std::forward<Args>(args)...);
  }

};

#endif
<|endoftext|>