<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2017 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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 <net/conntrack.hpp>
#include <set>

//#define CT_DEBUG 1
#ifdef CT_DEBUG
#define CTDBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define CTDBG(fmt, ...) /* fmt */
#endif

namespace net {

std::string proto_str(const Protocol proto)
{
  switch(proto) {
    case Protocol::TCP: return "TCP";
    case Protocol::UDP: return "UDP";
    case Protocol::ICMPv4: return "ICMPv4";
    default: return "???";
  }
}

std::string state_str(const Conntrack::State state)
{
  switch(state) {
    case Conntrack::State::NEW: return "NEW";
    case Conntrack::State::ESTABLISHED: return "EST";
    case Conntrack::State::RELATED: return "RELATED";
    case Conntrack::State::UNCONFIRMED: return "UNCONFIRMED";
    default: return "???";
  }
}

std::string flag_str(const uint8_t flags)
{
  std::string str;
  if(flags & static_cast<uint8_t>(Conntrack::Flag::UNREPLIED))
    str.append(" UNREPLIED");
  if(flags & static_cast<uint8_t>(Conntrack::Flag::ASSURED))
    str.append(" ASSURED");
  return str;
}

std::string Conntrack::Entry::to_string() const
{
  return "[ " + first.to_string() + " ] [ " + second.to_string() + " ]"
    + " P: " + proto_str(proto) + " S: " + state_str(state) + " F:" + flag_str(flags);
}

Conntrack::Entry::~Entry()
{
  if(this->on_close)
    on_close(this);
}

Conntrack::Entry* Conntrack::simple_track_in(Quadruple q, const Protocol proto)
{
  // find the entry
  auto* entry = get(q, proto);

  CTDBG("<Conntrack> Track in S: %s - D: %s\n",
    q.src.to_string().c_str(), q.dst.to_string().c_str());

  // if none, add new and return
  if(entry == nullptr)
  {
    entry = add_entry(q, proto);
    return entry;
  }

  // temp
  CTDBG("<Conntrack> Entry found: %s\n", entry->to_string().c_str());

  if(entry->state == State::NEW and q == entry->second)
  {
    entry->state = State::ESTABLISHED;
    CTDBG("<Conntrack> Assuming ESTABLISHED\n");
  }

  update_timeout(*entry, (entry->state == State::ESTABLISHED) ? timeout.established : timeout.confirmed);

  return entry;
}

Conntrack::Entry* dumb_in(Conntrack& ct, Quadruple q, const PacketIP4& pkt)
{ return  ct.simple_track_in(std::move(q), pkt.ip_protocol()); }

Conntrack::Conntrack()
 : Conntrack(0)
{}

Conntrack::Conntrack(size_t max_entries)
 : maximum_entries{max_entries},
   tcp_in{&dumb_in},
   flush_timer({this, &Conntrack::on_timeout})
{
}

Conntrack::Entry* Conntrack::get(const PacketIP4& pkt) const
{
  const auto proto = pkt.ip_protocol();
  switch(proto)
  {
    case Protocol::TCP:
    case Protocol::UDP:
      return get(get_quadruple(pkt), proto);

    case Protocol::ICMPv4:
      return get(get_quadruple_icmp(pkt), proto);

    default:
      return nullptr;
  }
}

Conntrack::Entry* Conntrack::get(const Quadruple& quad, const Protocol proto) const
{
  auto it = entries.find({quad, proto});

  if(it != entries.end())
    return it->second.get();

  return nullptr;
}

Quadruple Conntrack::get_quadruple(const PacketIP4& pkt)
{
  const auto* ports = reinterpret_cast<const uint16_t*>(pkt.ip_data().data());
  uint16_t src_port = ntohs(*ports);
  uint16_t dst_port = ntohs(*(ports + 1));

  return {{pkt.ip_src(), src_port}, {pkt.ip_dst(), dst_port}};
}

Quadruple Conntrack::get_quadruple_icmp(const PacketIP4& pkt)
{
  Expects(pkt.ip_protocol() == Protocol::ICMPv4);

  struct partial_header {
    uint16_t  type_code;
    uint16_t  checksum;
    uint16_t  id;
  };

  // not sure if sufficent
  auto id = reinterpret_cast<const partial_header*>(pkt.ip_data().data())->id;

  return {{pkt.ip_src(), id}, {pkt.ip_dst(), id}};
}

Conntrack::Entry* Conntrack::in(const PacketIP4& pkt)
{
  const auto proto = pkt.ip_protocol();
  switch(proto)
  {
    case Protocol::TCP:
      return tcp_in(*this, get_quadruple(pkt), pkt);

    case Protocol::UDP:
      return simple_track_in(get_quadruple(pkt), proto);

    case Protocol::ICMPv4:
      return simple_track_in(get_quadruple_icmp(pkt), proto);

    default:
      return nullptr;
  }
}

Conntrack::Entry* Conntrack::confirm(const PacketIP4& pkt)
{
  const auto proto = pkt.ip_protocol();

  auto quad = [&]()->Quadruple {
    switch(proto)
    {
      case Protocol::TCP:
      case Protocol::UDP:
        return get_quadruple(pkt);

      case Protocol::ICMPv4:
        return get_quadruple_icmp(pkt);

      default:
        return Quadruple();
    }
  }();

  return confirm(quad, proto);
}

Conntrack::Entry* Conntrack::confirm(Quadruple quad, const Protocol proto)
{
  auto* entry = get(quad, proto);

  if(UNLIKELY(entry == nullptr)) {
    CTDBG("<Conntrack> Entry not found on confirm, checking swapped: %s\n",
      quad.to_string().c_str());
    // the packet my be NATed. note: not sure if this is good
    if(UNLIKELY((entry = get(quad.swap(), proto)) == nullptr)) {
      return nullptr;
    }
  }

  if(entry->state == State::UNCONFIRMED)
  {
    CTDBG("<Conntrack> Confirming %s\n", entry->to_string().c_str());
    entry->state = State::NEW;
    update_timeout(*entry, timeout.confirmed);
  }

  return entry;
}

Conntrack::Entry* Conntrack::add_entry(
  const Quadruple& quad, const Protocol proto)
{
  // Return nullptr if conntrack is full
  if(UNLIKELY(maximum_entries != 0 and
    entries.size() + 2 > maximum_entries))
  {
    CTDBG("<Conntrack> Limit reached (limit=%lu sz=%lu)\n",
      maximum_entries, entries.size());
    return nullptr;
  }

  if(not flush_timer.is_running())
    flush_timer.start(flush_interval);

  // we dont check if it's already exists
  // because it should be called from in()

  // create the entry
  auto entry = std::make_shared<Entry>(quad, proto);

  entries.emplace(std::piecewise_construct,
    std::forward_as_tuple(entry->first, proto),
    std::forward_as_tuple(entry));

  entries.emplace(std::piecewise_construct,
    std::forward_as_tuple(entry->second, proto),
    std::forward_as_tuple(entry));

  CTDBG("<Conntrack> Entry added: %s\n", entry->to_string().c_str());

  update_timeout(*entry, timeout.unconfirmed);

  return entry.get();
}

Conntrack::Entry* Conntrack::update_entry(
  const Protocol proto, const Quadruple& oldq, const Quadruple& newq)
{
  // find the entry that has quintuple containing the old quant
  const auto quint = Quintuple{oldq, proto};
  auto it = entries.find(quint);

  if(UNLIKELY(it == entries.end())) {
    CTDBG("<Conntrack> Cannot find entry when updating: %s\n",
      oldq.to_string().c_str());
    return nullptr;
  }

  auto entry = it->second;

  // determine if the old quant hits the first or second quantuple
  auto& quad = (entry->first == oldq)
    ? entry->first : entry->second;

  // give it a new value
  quad = newq;

  // TODO: this could probably be optimized with C++17 map::extract
  // erase the old entry
  entries.erase(quint);
  // insert the entry with updated quintuple
  entries.emplace(std::piecewise_construct,
    std::forward_as_tuple(newq, proto),
    std::forward_as_tuple(entry));

  CTDBG("<Conntrack> Entry updated: %s\n", entry->to_string().c_str());

  return entry.get();
}

void Conntrack::remove_expired()
{
  CTDBG("<Conntrack> Removing expired entries\n");
  const auto NOW = RTC::now();
  // entries data structure
  for(auto it = entries.begin(); it != entries.end();)
  {
    if(it->second->timeout > NOW) {
      ++it;
    }
    else {
      CTDBG("<Conntrack> Erasing %s\n", it->second->to_string().c_str());
      it = entries.erase(it);
    }
  }
}

void Conntrack::on_timeout()
{
  remove_expired();

  if(not entries.empty())
    flush_timer.restart(flush_interval);
}

int Conntrack::Entry::deserialize_from(void* addr)
{
  auto& entry = *reinterpret_cast<Entry*>(addr);
  this->first   = entry.first;
  this->second  = entry.second;
  this->timeout = entry.timeout;
  this->proto   = entry.proto;
  this->state   = entry.state;
  this->flags   = entry.flags;
  this->other   = entry.other;
  return sizeof(Entry) - sizeof(on_close);
}

void Conntrack::Entry::serialize_to(std::vector<char>& buf) const
{
  const size_t size = sizeof(Entry) - sizeof(on_close);
  const auto* ptr = reinterpret_cast<const char*>(this);
  buf.insert(buf.end(), ptr, ptr + size);
}

int Conntrack::deserialize_from(void* addr)
{
  const auto prev_size = entries.size();
  auto* buffer = reinterpret_cast<uint8_t*>(addr);

  const auto size = *reinterpret_cast<size_t*>(buffer);
  buffer += sizeof(size_t);

  for(auto i = size; i > 0; i--)
  {
    // create the entry
    auto entry = std::make_shared<Entry>();
    buffer += entry->deserialize_from(buffer);

    entries.emplace(std::piecewise_construct,
      std::forward_as_tuple(entry->first, entry->proto),
      std::forward_as_tuple(entry));

    entries.emplace(std::piecewise_construct,
      std::forward_as_tuple(entry->second, entry->proto),
      std::forward_as_tuple(entry));
  }

  Ensures(entries.size() - prev_size == size * 2);

  return buffer - reinterpret_cast<uint8_t*>(addr);
}

void Conntrack::serialize_to(std::vector<char>& buf) const
{
  int unserialized = 0;

  // Since each entry is stored twice in the map,
  // we iterate and put it in a set if not already there
  std::set<Entry*> to_serialize;
  for(auto& i : entries)
  {
    auto* ent = i.second.get();

    // We cannot restore delegates, so just ignore
    // the ones with close handler set
    if(ent->on_close != nullptr) {
      unserialized++;
      continue;
    }
    // If not in set, add
    if(to_serialize.find(ent) == to_serialize.end())
      to_serialize.emplace(ent);
  }

  // Serialize number of entries
  size_t size = to_serialize.size();
  const auto* size_ptr = reinterpret_cast<const char*>(&size);

  const auto expected_buf_size = sizeof(size) + (size * (sizeof(Entry) - sizeof(Entry_handler)));
  buf.reserve(expected_buf_size);

  buf.insert(buf.end(), size_ptr, size_ptr + sizeof(size));
  // Serialize each entry
  for(auto& ent : to_serialize)
    ent->serialize_to(buf);

  if(unserialized > 0)
    INFO("Conntrack", "%i entries not serialized\n", unserialized);
}

}
<commit_msg>Correct connection tracking cherry picked from ipv6<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2017 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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 <net/conntrack.hpp>
#include <set>

//#define CT_DEBUG 1
#ifdef CT_DEBUG
#define CTDBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define CTDBG(fmt, ...) /* fmt */
#endif

namespace net {

std::string proto_str(const Protocol proto)
{
  switch(proto) {
    case Protocol::TCP: return "TCP";
    case Protocol::UDP: return "UDP";
    case Protocol::ICMPv4: return "ICMPv4";
    default: return "???";
  }
}

std::string state_str(const Conntrack::State state)
{
  switch(state) {
    case Conntrack::State::NEW: return "NEW";
    case Conntrack::State::ESTABLISHED: return "EST";
    case Conntrack::State::RELATED: return "RELATED";
    case Conntrack::State::UNCONFIRMED: return "UNCONFIRMED";
    default: return "???";
  }
}

std::string flag_str(const uint8_t flags)
{
  std::string str;
  if(flags & static_cast<uint8_t>(Conntrack::Flag::UNREPLIED))
    str.append(" UNREPLIED");
  if(flags & static_cast<uint8_t>(Conntrack::Flag::ASSURED))
    str.append(" ASSURED");
  return str;
}

std::string Conntrack::Entry::to_string() const
{
  return "[ " + first.to_string() + " ] [ " + second.to_string() + " ]"
    + " P: " + proto_str(proto) + " S: " + state_str(state) + " F:" + flag_str(flags);
}

Conntrack::Entry::~Entry()
{
  if(this->on_close)
    on_close(this);
}

Conntrack::Entry* Conntrack::simple_track_in(Quadruple q, const Protocol proto)
{
  // find the entry
  auto* entry = get(q, proto);

  CTDBG("<Conntrack> Track in S: %s - D: %s\n",
    q.src.to_string().c_str(), q.dst.to_string().c_str());

  // if none, add new and return
  if(entry == nullptr)
  {
    entry = add_entry(q, proto);
    return entry;
  }

  // temp
  CTDBG("<Conntrack> Entry found: %s\n", entry->to_string().c_str());

  if(entry->state == State::NEW and q == entry->second)
  {
    entry->state = State::ESTABLISHED;
    CTDBG("<Conntrack> Assuming ESTABLISHED\n");
  }

  update_timeout(*entry, (entry->state == State::ESTABLISHED) ? timeout.established : timeout.confirmed);

  return entry;
}

Conntrack::Entry* dumb_in(Conntrack& ct, Quadruple q, const PacketIP4& pkt)
{ return  ct.simple_track_in(std::move(q), pkt.ip_protocol()); }

Conntrack::Conntrack()
 : Conntrack(0)
{}

Conntrack::Conntrack(size_t max_entries)
 : maximum_entries{max_entries},
   tcp_in{&dumb_in},
   flush_timer({this, &Conntrack::on_timeout})
{
}

Conntrack::Entry* Conntrack::get(const PacketIP4& pkt) const
{
  const auto proto = pkt.ip_protocol();
  switch(proto)
  {
    case Protocol::TCP:
    case Protocol::UDP:
      return get(get_quadruple(pkt), proto);

    case Protocol::ICMPv4:
      return get(get_quadruple_icmp(pkt), proto);

    default:
      return nullptr;
  }
}

Conntrack::Entry* Conntrack::get(const Quadruple& quad, const Protocol proto) const
{
  auto it = entries.find({quad, proto});

  if(it != entries.end())
    return it->second.get();

  return nullptr;
}

Quadruple Conntrack::get_quadruple(const PacketIP4& pkt)
{
  const auto* ports = reinterpret_cast<const uint16_t*>(pkt.ip_data().data());
  uint16_t src_port = ntohs(*ports);
  uint16_t dst_port = ntohs(*(ports + 1));

  return {{pkt.ip_src(), src_port}, {pkt.ip_dst(), dst_port}};
}

Quadruple Conntrack::get_quadruple_icmp(const PacketIP4& pkt)
{
  Expects(pkt.ip_protocol() == Protocol::ICMPv4);

  struct partial_header {
    uint16_t  type_code;
    uint16_t  checksum;
    uint16_t  id;
  };

  // not sure if sufficent
  auto id = reinterpret_cast<const partial_header*>(pkt.ip_data().data())->id;

  return {{pkt.ip_src(), id}, {pkt.ip_dst(), id}};
}

Conntrack::Entry* Conntrack::in(const PacketIP4& pkt)
{
  const auto proto = pkt.ip_protocol();
  switch(proto)
  {
    case Protocol::TCP:
      return tcp_in(*this, get_quadruple(pkt), pkt);

    case Protocol::UDP:
      return simple_track_in(get_quadruple(pkt), proto);

    case Protocol::ICMPv4:
      return simple_track_in(get_quadruple_icmp(pkt), proto);

    default:
      return nullptr;
  }
}

Conntrack::Entry* Conntrack::confirm(const PacketIP4& pkt)
{
  const auto proto = pkt.ip_protocol();

  auto quad = [&]()->Quadruple {
    switch(proto)
    {
      case Protocol::TCP:
      case Protocol::UDP:
        return get_quadruple(pkt);

      case Protocol::ICMPv4:
        return get_quadruple_icmp(pkt);

      default:
        return Quadruple();
    }
  }();

  return confirm(quad, proto);
}

Conntrack::Entry* Conntrack::confirm(Quadruple quad, const Protocol proto)
{
  auto* entry = get(quad, proto);

  if(UNLIKELY(entry == nullptr)) {
    CTDBG("<Conntrack> Entry not found on confirm, checking swapped: %s\n",
      quad.to_string().c_str());
    // the packet my be NATed. note: not sure if this is good
    if(UNLIKELY((entry = get(quad.swap(), proto)) == nullptr)) {
      return nullptr;
    }
  }

  if(entry->state == State::UNCONFIRMED)
  {
    CTDBG("<Conntrack> Confirming %s\n", entry->to_string().c_str());
    entry->state = State::NEW;
    update_timeout(*entry, timeout.confirmed);
  }

  return entry;
}

Conntrack::Entry* Conntrack::add_entry(
  const Quadruple& quad, const Protocol proto)
{
  // Return nullptr if conntrack is full
  if(UNLIKELY(maximum_entries != 0 and
    entries.size() + 2 > maximum_entries))
  {
    CTDBG("<Conntrack> Limit reached (limit=%lu sz=%lu)\n",
      maximum_entries, entries.size());
    return nullptr;
  }

  if(not flush_timer.is_running())
    flush_timer.start(flush_interval);

  // we dont check if it's already exists
  // because it should be called from in()

  // create the entry
  auto entry = std::make_shared<Entry>(quad, proto);

  entries.emplace(std::piecewise_construct,
    std::forward_as_tuple(entry->first, proto),
    std::forward_as_tuple(entry));

  entries.emplace(std::piecewise_construct,
    std::forward_as_tuple(entry->second, proto),
    std::forward_as_tuple(entry));

  CTDBG("<Conntrack> Entry added: %s\n", entry->to_string().c_str());

  update_timeout(*entry, timeout.unconfirmed);

  return entry.get();
}

Conntrack::Entry* Conntrack::update_entry(
  const Protocol proto, const Quadruple& oldq, const Quadruple& newq)
{
  // find the entry that has quintuple containing the old quant
  const auto quint = Quintuple{oldq, proto};
  auto it = entries.find(quint);

  if(UNLIKELY(it == entries.end())) {
    CTDBG("<Conntrack> Cannot find entry when updating: %s\n",
      oldq.to_string().c_str());
    return nullptr;
  }

  auto entry = it->second;

  // determine if the old quant hits the first or second quantuple
  auto& quad = (entry->first == oldq)
    ? entry->first : entry->second;

  // give it a new value
  quad = newq;

  // TODO: this could probably be optimized with C++17 map::extract
  // erase the old entry
  entries.erase(quint);
  // insert the entry with updated quintuple
  entries.emplace(std::piecewise_construct,
    std::forward_as_tuple(newq, proto),
    std::forward_as_tuple(entry));

  CTDBG("<Conntrack> Entry updated: %s\n", entry->to_string().c_str());

  return entry.get();
}

void Conntrack::remove_expired()
{
  CTDBG("<Conntrack> Removing expired entries\n");
  const auto NOW = RTC::now();
  // entries data structure
  for(auto it = entries.begin(); it != entries.end();)
  {
    if(it->second->timeout > NOW) {
      ++it;
    }
    else {
      CTDBG("<Conntrack> Erasing %s\n", it->second->to_string().c_str());
      it = entries.erase(it);
    }
  }
}

void Conntrack::on_timeout()
{
  remove_expired();

  if(not entries.empty())
    flush_timer.restart(flush_interval);
}

int Conntrack::Entry::deserialize_from(void* addr)
{
  auto& entry = *reinterpret_cast<Entry*>(addr);
  this->first   = entry.first;
  this->second  = entry.second;
  this->timeout = entry.timeout;
  this->proto   = entry.proto;
  this->state   = entry.state;
  this->flags   = entry.flags;
  this->other   = entry.other;
  return sizeof(Entry) - sizeof(on_close);
}

void Conntrack::Entry::serialize_to(std::vector<char>& buf) const
{
  const size_t size = sizeof(Entry) - sizeof(on_close);
  const auto* ptr = reinterpret_cast<const char*>(this);
  buf.insert(buf.end(), ptr, ptr + size);
}

int Conntrack::deserialize_from(void* addr)
{
  const auto prev_size = entries.size();
  auto* buffer = reinterpret_cast<uint8_t*>(addr);

  const auto size = *reinterpret_cast<size_t*>(buffer);
  buffer += sizeof(size_t);
  size_t dupes = 0;
  for(auto i = size; i > 0; i--)
  {
    // create the entry
    auto entry = std::make_shared<Entry>();
    buffer += entry->deserialize_from(buffer);

    bool insert = false;
    insert = entries.insert_or_assign({entry->first, entry->proto}, entry).second;
    if(not insert)
      dupes++;
    insert = entries.insert_or_assign({entry->second, entry->proto}, entry).second;
    if(not insert)
      dupes++;
  }
  Ensures(entries.size() - (prev_size-dupes) == size * 2);

  return buffer - reinterpret_cast<uint8_t*>(addr);
}

void Conntrack::serialize_to(std::vector<char>& buf) const
{
  int unserialized = 0;

  // Since each entry is stored twice in the map,
  // we iterate and put it in a set if not already there
  std::set<Entry*> to_serialize;
  for(auto& i : entries)
  {
    auto* ent = i.second.get();

    // We cannot restore delegates, so just ignore
    // the ones with close handler set
    if(ent->on_close != nullptr) {
      unserialized++;
      continue;
    }
    // If not in set, add
    if(to_serialize.find(ent) == to_serialize.end())
      to_serialize.emplace(ent);
  }

  // Serialize number of entries
  size_t size = to_serialize.size();
  const auto* size_ptr = reinterpret_cast<const char*>(&size);

  const auto expected_buf_size = sizeof(size) + (size * (sizeof(Entry) - sizeof(Entry_handler)));
  buf.reserve(expected_buf_size);

  buf.insert(buf.end(), size_ptr, size_ptr + sizeof(size));
  // Serialize each entry
  for(auto& ent : to_serialize)
    ent->serialize_to(buf);

  if(unserialized > 0)
    INFO("Conntrack", "%i entries not serialized\n", unserialized);
}

}
<|endoftext|>


<commit_before>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2014, Willow Garage, Inc.
 *  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 Willow Garage 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 OWNER 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.
 *********************************************************************/

/* Author: Arjun Menon */

#include <ros/ros.h>

#include <moveit/move_group_interface/move_group.h>

#include <moveit/warehouse/planning_scene_storage.h>

#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#include <view_controller_msgs/CameraPlacement.h>

#include "moveit_recorder/trajectory_retimer.h"
#include "moveit_recorder/animation_recorder.h"
#include "moveit_recorder/utils.h"

#include <rosbag/bag.h>
#include <rosbag/query.h>
#include <rosbag/view.h>

#include <algorithm>

int main(int argc, char** argv)
{
  ros::init(argc, argv, "playback");
  ros::NodeHandle node_handle;
  ros::AsyncSpinner spinner(1);
  spinner.start();

  sleep(20); // to let RVIZ come up

  boost::program_options::options_description desc;
  desc.add_options()
    ("help", "Show help message")
    ("host", boost::program_options::value<std::string>(), "Host for the MongoDB.")
    ("port", boost::program_options::value<std::size_t>(), "Port for the MongoDB.")
    ("views",boost::program_options::value<std::string>(), "Bag file for viewpoints")
    ("camera_topic",boost::program_options::value<std::string>(), "Topic for publishing to the camera position")
    ("planning_scene_topic",boost::program_options::value<std::string>(), "Topic for publishing the planning scene for recording")
    ("display_traj_topic",boost::program_options::value<std::string>(), "Topic for publishing the trajectory for recorder")
    ("animation_status_topic",boost::program_options::value<std::string>(), "Topic for listening to the completion of the replay")
    ("save_dir",boost::program_options::value<std::string>(), "Directory for saving videos");

  boost::program_options::variables_map vm;
  boost::program_options::parsed_options po = boost::program_options::parse_command_line(argc, argv, desc);
  boost::program_options::store(po, vm);
  boost::program_options::notify(vm);

  if (vm.count("help") || argc == 1) // show help if no parameters passed
  {
    std::cout << desc << std::endl;
    return 1;
  }
  try
  {
    //connect to the DB
    std::string host = vm.count("host") ? vm["host"].as<std::string>() : "";
    size_t port = vm.count("port") ? vm["port"].as<std::size_t>() : 0;
    moveit_warehouse::PlanningSceneStorage pss(host, port);
    ROS_INFO("Connected to Warehouse DB at host (%s) and port (%d)", host.c_str(), (int)port);

    // set up the storage directory
    boost::filesystem::path storage_dir( vm.count("save_dir") ? vm["save_dir"].as<std::string>() : "/tmp" );
    boost::filesystem::create_directories( storage_dir );

    // create bag file to track the associated video to the scene, query, and traj that spawned it
    boost::filesystem::path bagpath = storage_dir / "video_lookup.bag";
    rosbag::Bag bag(bagpath.string(), rosbag::bagmode::Write);
    bag.close();

    // load the viewpoints
    std::string bagfilename = vm.count("views") ? vm["views"].as<std::string>() : "";
    std::vector<view_controller_msgs::CameraPlacement> views;
    rosbag::Bag viewbag;
    viewbag.open(bagfilename, rosbag::bagmode::Read);
    std::vector<std::string> topics; topics.push_back("viewpoints");
    rosbag::View view_t(viewbag, rosbag::TopicQuery(topics));
    BOOST_FOREACH(rosbag::MessageInstance const m, view_t)
    {
      view_controller_msgs::CameraPlacement::ConstPtr i = m.instantiate<view_controller_msgs::CameraPlacement>();
      if (i != NULL)
        views.push_back(*i);
    }
    viewbag.close();
    ROS_INFO("%d views loaded",(int)views.size());

    //TODO change these to params
    std::string camera_placement_topic = utils::get_option(vm, "camera_topic", "/rviz/camera_placement");
    std::string planning_scene_topic =utils:: get_option(vm, "planning_scene_topic", "planning_scene");
    std::string display_traj_topic = utils::get_option(vm, "display_traj_topic", "/move_group/display_planned_path");
    std::string anim_status_topic = utils::get_option(vm, "animation_status_topic", "animation_status");

    AnimationRecorder recorder( camera_placement_topic,
                                planning_scene_topic,
                                display_traj_topic,
                                anim_status_topic,
                                node_handle);

    // ask the warehouse for the scenes
    std::vector<std::string> ps_names;
    pss.getPlanningSceneNames( ps_names );
    ROS_INFO("%d available scenes to display", (int)ps_names.size());

    // iterate over scenes
    std::vector<std::string>::iterator scene_name = ps_names.begin();
    for(; scene_name!=ps_names.end(); ++scene_name)
    {
      ROS_INFO("Retrieving scene %s", scene_name->c_str());
      moveit_warehouse::PlanningSceneWithMetadata pswm;
      pss.getPlanningScene(pswm, *scene_name);
      moveit_msgs::PlanningScene ps_msg = static_cast<const moveit_msgs::PlanningScene&>(*pswm);

      // ask qarehosue for the queries
      std::vector<std::string> pq_names;
      pss.getPlanningQueriesNames( pq_names, *scene_name);
      ROS_INFO("%d available queries to display", (int)pq_names.size());

      // iterate over the queries
      std::vector<std::string>::iterator query_name = pq_names.begin();
      for(; query_name!=pq_names.end(); ++query_name)
      {
        ROS_INFO("Retrieving query %s", query_name->c_str());
        moveit_warehouse::MotionPlanRequestWithMetadata mprwm;
        pss.getPlanningQuery(mprwm, *scene_name, *query_name);
        moveit_msgs::MotionPlanRequest mpr_msg = static_cast<const moveit_msgs::MotionPlanRequest&>(*mprwm);

        // ask warehouse for stored trajectories
        std::vector<moveit_warehouse::RobotTrajectoryWithMetadata> planning_results;
        pss.getPlanningResults(planning_results, *scene_name, *query_name);
        ROS_INFO("Loaded %d trajectories", (int)planning_results.size());

        // animate each trajectory
        std::vector<moveit_warehouse::RobotTrajectoryWithMetadata>::iterator traj_w_mdata = planning_results.begin();
        for(; traj_w_mdata!=planning_results.end(); ++traj_w_mdata)
        {
          moveit_msgs::RobotTrajectory rt_msg;
          rt_msg = static_cast<const moveit_msgs::RobotTrajectory&>(**traj_w_mdata);
          // retime it
          TrajectoryRetimer retimer( "robot_description", mpr_msg.group_name );
          retimer.configure(ps_msg, mpr_msg);
          bool result = retimer.retime(rt_msg);
          ROS_INFO("Retiming success? %s", result? "yes" : "no" );

          //date and time based filename
          boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
          std::string vid_filename = boost::posix_time::to_simple_string(now);

          // fix filename
          std::replace(vid_filename.begin(), vid_filename.end(), '-','_');
          std::replace(vid_filename.begin(), vid_filename.end(), ' ','_');
          std::replace(vid_filename.begin(), vid_filename.end(), ':','_');

          boost::filesystem::path filename( vid_filename );
          boost::filesystem::path filepath = storage_dir / filename;

          // fix topic name
          std::string topicname = filename.string();
          std::replace(topicname.begin(), topicname.end(), '/','_');
          std::replace(topicname.begin(), topicname.end(), '-','_');
          std::replace(topicname.begin(), topicname.end(), ' ','_');
          std::replace(topicname.begin(), topicname.end(), ':','_');

          // save into lookup
          // topics for videos are /ps/xxxx/ for the planning scene
          //                       /mpr/xxxx/ for the motion plan request
          //                       /rt/xxxx/ for the robot trajectory
          //                       /vid/xxxx/ for the videos
          rosbag::Bag bag(bagpath.string(), rosbag::bagmode::Append);
          bag.write<moveit_msgs::PlanningScene>( (boost::filesystem::path("/ps")/topicname).string(),
                                                  ros::Time::now(), ps_msg);
          bag.write<moveit_msgs::MotionPlanRequest>( (boost::filesystem::path("/mpr")/topicname).string(),
                                                    ros::Time::now(), mpr_msg);
          bag.write<moveit_msgs::RobotTrajectory>( (boost::filesystem::path("/rt")/topicname).string(),
                                                  ros::Time::now(), rt_msg);

          int view_counter=0;
          std::vector<view_controller_msgs::CameraPlacement>::iterator view_msg;
          for(view_msg=views.begin(); view_msg!=views.end(); ++view_msg)
          {
            AnimationRequest req;

            view_msg->time_from_start = ros::Duration(0.1);
            ros::Time t_now = ros::Time::now();
            view_msg->eye.header.stamp = t_now;
            view_msg->focus.header.stamp = t_now;
            view_msg->up.header.stamp = t_now;

            req.camera_placement = *view_msg;
            req.planning_scene = ps_msg;
            req.motion_plan_request = mpr_msg;
            req.robot_trajectory = rt_msg;

            // same filename, counter for viewpoint
            std::string ext = boost::lexical_cast<std::string>(view_counter++) + ".ogv";
            std::string video_file = filepath.string()+ext;
            req.filepath = video_file;
            std::string topicview = "view"+boost::lexical_cast<std::string>(view_counter);

            // save to bag
            std_msgs::String filemsg; filemsg.data = req.filepath;
            bag.write<std_msgs::String>( ((boost::filesystem::path("/vid")/topicname)/topicview).string(),
                                          ros::Time::now(), filemsg);

            recorder.record(req);
            recorder.startCapture();
            ROS_INFO("RECORDING DONE!");
          }//view
          bag.close();
        }//traj
      }//query
    }//scene
  }
  catch(mongo_ros::DbConnectException &ex)
  {
    ROS_ERROR_STREAM("Unable to connect to warehouse. If you just created the database, it could take a while for initial setup. Please try to run the benchmark again."
        << std::endl << ex.what());
  }

  ROS_INFO("Successfully performed trajectory playback");
  ros::shutdown();
  return 0;
}
<commit_msg>tweaked camera move speed, and added a commment line<commit_after>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2014, Willow Garage, Inc.
 *  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 Willow Garage 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 OWNER 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.
 *********************************************************************/

/* Author: Arjun Menon */

#include <ros/ros.h>

#include <moveit/move_group_interface/move_group.h>

#include <moveit/warehouse/planning_scene_storage.h>

#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#include <view_controller_msgs/CameraPlacement.h>

#include "moveit_recorder/trajectory_retimer.h"
#include "moveit_recorder/animation_recorder.h"
#include "moveit_recorder/utils.h"

#include <rosbag/bag.h>
#include <rosbag/query.h>
#include <rosbag/view.h>

#include <algorithm>

int main(int argc, char** argv)
{
  ros::init(argc, argv, "playback");
  ros::NodeHandle node_handle;
  ros::AsyncSpinner spinner(1);
  spinner.start();

  sleep(20); // to let RVIZ come up

  boost::program_options::options_description desc;
  desc.add_options()
    ("help", "Show help message")
    ("host", boost::program_options::value<std::string>(), "Host for the MongoDB.")
    ("port", boost::program_options::value<std::size_t>(), "Port for the MongoDB.")
    ("views",boost::program_options::value<std::string>(), "Bag file for viewpoints")
    ("camera_topic",boost::program_options::value<std::string>(), "Topic for publishing to the camera position")
    ("planning_scene_topic",boost::program_options::value<std::string>(), "Topic for publishing the planning scene for recording")
    ("display_traj_topic",boost::program_options::value<std::string>(), "Topic for publishing the trajectory for recorder")
    ("animation_status_topic",boost::program_options::value<std::string>(), "Topic for listening to the completion of the replay")
    ("save_dir",boost::program_options::value<std::string>(), "Directory for saving videos");

  boost::program_options::variables_map vm;
  boost::program_options::parsed_options po = boost::program_options::parse_command_line(argc, argv, desc);
  boost::program_options::store(po, vm);
  boost::program_options::notify(vm);

  if (vm.count("help") || argc == 1) // show help if no parameters passed
  {
    std::cout << desc << std::endl;
    return 1;
  }
  try
  {
    //connect to the DB
    std::string host = vm.count("host") ? vm["host"].as<std::string>() : "";
    size_t port = vm.count("port") ? vm["port"].as<std::size_t>() : 0;
    moveit_warehouse::PlanningSceneStorage pss(host, port);
    ROS_INFO("Connected to Warehouse DB at host (%s) and port (%d)", host.c_str(), (int)port);

    // set up the storage directory
    boost::filesystem::path storage_dir( vm.count("save_dir") ? vm["save_dir"].as<std::string>() : "/tmp" );
    boost::filesystem::create_directories( storage_dir );

    // create bag file to track the associated video to the scene, query, and traj that spawned it
    boost::filesystem::path bagpath = storage_dir / "video_lookup.bag";
    rosbag::Bag bag(bagpath.string(), rosbag::bagmode::Write);
    bag.close();

    // load the viewpoints
    std::string bagfilename = vm.count("views") ? vm["views"].as<std::string>() : "";
    std::vector<view_controller_msgs::CameraPlacement> views;
    rosbag::Bag viewbag;
    viewbag.open(bagfilename, rosbag::bagmode::Read);
    std::vector<std::string> topics; topics.push_back("viewpoints");
    rosbag::View view_t(viewbag, rosbag::TopicQuery(topics));
    BOOST_FOREACH(rosbag::MessageInstance const m, view_t)
    {
      view_controller_msgs::CameraPlacement::ConstPtr i = m.instantiate<view_controller_msgs::CameraPlacement>();
      if (i != NULL)
        views.push_back(*i);
    }
    viewbag.close();
    ROS_INFO("%d views loaded",(int)views.size());

    //TODO change these to params
    std::string camera_placement_topic = utils::get_option(vm, "camera_topic", "/rviz/camera_placement");
    std::string planning_scene_topic =utils:: get_option(vm, "planning_scene_topic", "planning_scene");
    std::string display_traj_topic = utils::get_option(vm, "display_traj_topic", "/move_group/display_planned_path");
    std::string anim_status_topic = utils::get_option(vm, "animation_status_topic", "animation_status");

    AnimationRecorder recorder( camera_placement_topic,
                                planning_scene_topic,
                                display_traj_topic,
                                anim_status_topic,
                                node_handle);

    // ask the warehouse for the scenes
    std::vector<std::string> ps_names;
    pss.getPlanningSceneNames( ps_names );
    ROS_INFO("%d available scenes to display", (int)ps_names.size());

    // iterate over scenes
    std::vector<std::string>::iterator scene_name = ps_names.begin();
    for(; scene_name!=ps_names.end(); ++scene_name)
    {
      ROS_INFO("Retrieving scene %s", scene_name->c_str());
      moveit_warehouse::PlanningSceneWithMetadata pswm;
      pss.getPlanningScene(pswm, *scene_name);
      moveit_msgs::PlanningScene ps_msg = static_cast<const moveit_msgs::PlanningScene&>(*pswm);

      // ask qarehosue for the queries
      std::vector<std::string> pq_names;
      pss.getPlanningQueriesNames( pq_names, *scene_name);
      ROS_INFO("%d available queries to display", (int)pq_names.size());

      // iterate over the queries
      std::vector<std::string>::iterator query_name = pq_names.begin();
      for(; query_name!=pq_names.end(); ++query_name)
      {
        ROS_INFO("Retrieving query %s", query_name->c_str());
        moveit_warehouse::MotionPlanRequestWithMetadata mprwm;
        pss.getPlanningQuery(mprwm, *scene_name, *query_name);
        moveit_msgs::MotionPlanRequest mpr_msg = static_cast<const moveit_msgs::MotionPlanRequest&>(*mprwm);

        // ask warehouse for stored trajectories
        std::vector<moveit_warehouse::RobotTrajectoryWithMetadata> planning_results;
        pss.getPlanningResults(planning_results, *scene_name, *query_name);
        ROS_INFO("Loaded %d trajectories", (int)planning_results.size());

        // animate each trajectory
        std::vector<moveit_warehouse::RobotTrajectoryWithMetadata>::iterator traj_w_mdata = planning_results.begin();
        for(; traj_w_mdata!=planning_results.end(); ++traj_w_mdata)
        {
          moveit_msgs::RobotTrajectory rt_msg;
          rt_msg = static_cast<const moveit_msgs::RobotTrajectory&>(**traj_w_mdata);
          // retime it
          TrajectoryRetimer retimer( "robot_description", mpr_msg.group_name );
          retimer.configure(ps_msg, mpr_msg);
          bool result = retimer.retime(rt_msg);
          ROS_INFO("Retiming success? %s", result? "yes" : "no" );

          //date and time based filename
          boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
          std::string vid_filename = boost::posix_time::to_simple_string(now);

          // fix filename
          std::replace(vid_filename.begin(), vid_filename.end(), '-','_');
          std::replace(vid_filename.begin(), vid_filename.end(), ' ','_');
          std::replace(vid_filename.begin(), vid_filename.end(), ':','_');

          boost::filesystem::path filename( vid_filename );
          boost::filesystem::path filepath = storage_dir / filename;

          // fix topic name
          std::string topicname = filename.string();
          std::replace(topicname.begin(), topicname.end(), '/','_');
          std::replace(topicname.begin(), topicname.end(), '-','_');
          std::replace(topicname.begin(), topicname.end(), ' ','_');
          std::replace(topicname.begin(), topicname.end(), ':','_');

          // save into lookup
          // topics for videos are /ps/xxxx/ for the planning scene
          //                       /mpr/xxxx/ for the motion plan request
          //                       /rt/xxxx/ for the robot trajectory
          //                       /vid/xxxx/viewx for the videos
          //                       /vid/xxxx/split for a split screen version
          rosbag::Bag bag(bagpath.string(), rosbag::bagmode::Append);
          bag.write<moveit_msgs::PlanningScene>( (boost::filesystem::path("/ps")/topicname).string(),
                                                  ros::Time::now(), ps_msg);
          bag.write<moveit_msgs::MotionPlanRequest>( (boost::filesystem::path("/mpr")/topicname).string(),
                                                    ros::Time::now(), mpr_msg);
          bag.write<moveit_msgs::RobotTrajectory>( (boost::filesystem::path("/rt")/topicname).string(),
                                                  ros::Time::now(), rt_msg);

          int view_counter=0;
          std::vector<view_controller_msgs::CameraPlacement>::iterator view_msg;
          for(view_msg=views.begin(); view_msg!=views.end(); ++view_msg)
          {
            AnimationRequest req;

            view_msg->time_from_start = ros::Duration(0.001);
            ros::Time t_now = ros::Time::now();
            view_msg->eye.header.stamp = t_now;
            view_msg->focus.header.stamp = t_now;
            view_msg->up.header.stamp = t_now;

            req.camera_placement = *view_msg;
            req.planning_scene = ps_msg;
            req.motion_plan_request = mpr_msg;
            req.robot_trajectory = rt_msg;

            // same filename, counter for viewpoint
            std::string ext = boost::lexical_cast<std::string>(view_counter++) + ".ogv";
            std::string video_file = filepath.string()+ext;
            req.filepath = video_file;
            std::string topicview = "view"+boost::lexical_cast<std::string>(view_counter);

            // save to bag
            std_msgs::String filemsg; filemsg.data = req.filepath;
            bag.write<std_msgs::String>( ((boost::filesystem::path("/vid")/topicname)/topicview).string(),
                                          ros::Time::now(), filemsg);

            recorder.record(req);
            recorder.startCapture();
            ROS_INFO("RECORDING DONE!");
          }//view
          bag.close();
        }//traj
      }//query
    }//scene
  }
  catch(mongo_ros::DbConnectException &ex)
  {
    ROS_ERROR_STREAM("Unable to connect to warehouse. If you just created the database, it could take a while for initial setup. Please try to run the benchmark again."
        << std::endl << ex.what());
  }

  ROS_INFO("Successfully performed trajectory playback");
  ros::shutdown();
  return 0;
}
<|endoftext|>


<commit_before>/*!
 * \author ddubois
 * \date 03-Sep-18.
 */

#include <future>

#include "nova_renderer.hpp"

#include "glslang/MachineIndependent/Initialize.h"
#include "loading/shaderpack/shaderpack_loading.hpp"

#if defined(NOVA_WINDOWS)
#include "render_engine/dx12/dx12_render_engine.hpp"
#endif

#include "debugging/renderdoc.hpp"
#include "render_engine/vulkan/vulkan_render_engine.hpp"

#include <minitrace/minitrace.h>

namespace nova::renderer {
    std::unique_ptr<nova_renderer> nova_renderer::instance;

    nova_renderer::nova_renderer(const settings_options& settings)
        : render_settings(settings), task_scheduler(1, nova::ttl::empty_queue_behavior::YIELD) {

        mtr_init("trace.json");

        MTR_META_PROCESS_NAME("NovaRenderer");
        MTR_META_THREAD_NAME("Main");

        MTR_SCOPE("Init", "nova_renderer::nova_renderer");

        if(settings.debug.renderdoc.enabled) {
            MTR_SCOPE("Init", "LoadRenderdoc");
            render_doc = load_renderdoc(settings.debug.renderdoc.renderdoc_dll_path);

            if(render_doc != nullptr) {
                render_doc->SetCaptureFilePathTemplate(settings.debug.renderdoc.capture_path.c_str());

                RENDERDOC_InputButton capture_key[] = {eRENDERDOC_Key_F12, eRENDERDOC_Key_PrtScrn};
                render_doc->SetCaptureKeys(capture_key, 1);

                render_doc->SetCaptureOptionU32(eRENDERDOC_Option_AllowFullscreen, 1U);
                render_doc->SetCaptureOptionU32(eRENDERDOC_Option_AllowVSync, 1U);
                render_doc->SetCaptureOptionU32(eRENDERDOC_Option_VerifyMapWrites, 1U);
                render_doc->SetCaptureOptionU32(eRENDERDOC_Option_SaveAllInitials, 1U);
                render_doc->SetCaptureOptionU32(eRENDERDOC_Option_APIValidation, 1U);
            }
        }

        switch(settings.api) {
            case graphics_api::dx12:
#if defined(NOVA_WINDOWS)
            {
                MTR_SCOPE("Init", "InitDirectX12RenderEngine");
                engine = std::make_unique<dx12_render_engine>(render_settings, &task_scheduler);
            } break;
#else
                NOVA_LOG(WARN) << "You selected the DX12 graphics API, but your system doesn't support it. Defaulting to Vulkan";
#endif
            case graphics_api::vulkan:
                MTR_SCOPE("Init", "InitVulkanRenderEngine");
                engine = std::make_unique<vulkan_render_engine>(render_settings, &task_scheduler);
        }
    }

    nova_renderer::~nova_renderer() { mtr_shutdown(); }

    nova_settings& nova_renderer::get_settings() { return render_settings; }

    void nova_renderer::execute_frame() const {
        MTR_SCOPE("RenderLoop", "execute_frame");
        engine->render_frame();

        mtr_flush();
    }

    void nova_renderer::load_shaderpack(const std::string& shaderpack_name) const {
        MTR_SCOPE("ShaderpackLoading", "load_shaderpack");
        glslang::InitializeProcess();

        const shaderpack_data shaderpack_data = load_shaderpack_data(fs::path(shaderpack_name));

        engine->set_shaderpack(shaderpack_data);
        NOVA_LOG(INFO) << "Shaderpack " << shaderpack_name << " loaded successfully";
    }

    render_engine* nova_renderer::get_engine() const { return engine.get(); }

    nova_renderer* nova_renderer::get_instance() { return instance.get(); }

    nova_renderer* nova_renderer::initialize(const settings_options& settings) {
        return (instance = std::make_unique<nova_renderer>(settings)).get();
    }

    void nova_renderer::deinitialize() { instance = nullptr; }

    nova::ttl::task_scheduler& nova_renderer::get_task_scheduler() { return task_scheduler; }
} // namespace nova::renderer
<commit_msg>Annotate intended fallthrough<commit_after>/*!
 * \author ddubois
 * \date 03-Sep-18.
 */

#include <future>

#include "nova_renderer.hpp"

#include "glslang/MachineIndependent/Initialize.h"
#include "loading/shaderpack/shaderpack_loading.hpp"

#if defined(NOVA_WINDOWS)
#include "render_engine/dx12/dx12_render_engine.hpp"
#endif

#include "debugging/renderdoc.hpp"
#include "render_engine/vulkan/vulkan_render_engine.hpp"

#include <minitrace/minitrace.h>

namespace nova::renderer {
    std::unique_ptr<nova_renderer> nova_renderer::instance;

    nova_renderer::nova_renderer(const settings_options& settings)
        : render_settings(settings), task_scheduler(1, nova::ttl::empty_queue_behavior::YIELD) {

        mtr_init("trace.json");

        MTR_META_PROCESS_NAME("NovaRenderer");
        MTR_META_THREAD_NAME("Main");

        MTR_SCOPE("Init", "nova_renderer::nova_renderer");

        if(settings.debug.renderdoc.enabled) {
            MTR_SCOPE("Init", "LoadRenderdoc");
            render_doc = load_renderdoc(settings.debug.renderdoc.renderdoc_dll_path);

            if(render_doc != nullptr) {
                render_doc->SetCaptureFilePathTemplate(settings.debug.renderdoc.capture_path.c_str());

                RENDERDOC_InputButton capture_key[] = {eRENDERDOC_Key_F12, eRENDERDOC_Key_PrtScrn};
                render_doc->SetCaptureKeys(capture_key, 1);

                render_doc->SetCaptureOptionU32(eRENDERDOC_Option_AllowFullscreen, 1U);
                render_doc->SetCaptureOptionU32(eRENDERDOC_Option_AllowVSync, 1U);
                render_doc->SetCaptureOptionU32(eRENDERDOC_Option_VerifyMapWrites, 1U);
                render_doc->SetCaptureOptionU32(eRENDERDOC_Option_SaveAllInitials, 1U);
                render_doc->SetCaptureOptionU32(eRENDERDOC_Option_APIValidation, 1U);
            }
        }

        switch(settings.api) {
            case graphics_api::dx12:
#if defined(NOVA_WINDOWS)
                {
                    MTR_SCOPE("Init", "InitDirectX12RenderEngine");
                    engine = std::make_unique<dx12_render_engine>(render_settings, &task_scheduler);
                } break;
#else
                NOVA_LOG(WARN) << "You selected the DX12 graphics API, but your system doesn't support it. Defaulting to Vulkan";
                [[fallthrough]];
#endif
            case graphics_api::vulkan:
                MTR_SCOPE("Init", "InitVulkanRenderEngine");
                engine = std::make_unique<vulkan_render_engine>(render_settings, &task_scheduler);
        }
    }

    nova_renderer::~nova_renderer() { mtr_shutdown(); }

    nova_settings& nova_renderer::get_settings() { return render_settings; }

    void nova_renderer::execute_frame() const {
        MTR_SCOPE("RenderLoop", "execute_frame");
        engine->render_frame();

        mtr_flush();
    }

    void nova_renderer::load_shaderpack(const std::string& shaderpack_name) const {
        MTR_SCOPE("ShaderpackLoading", "load_shaderpack");
        glslang::InitializeProcess();

        const shaderpack_data shaderpack_data = load_shaderpack_data(fs::path(shaderpack_name));

        engine->set_shaderpack(shaderpack_data);
        NOVA_LOG(INFO) << "Shaderpack " << shaderpack_name << " loaded successfully";
    }

    render_engine* nova_renderer::get_engine() const { return engine.get(); }

    nova_renderer* nova_renderer::get_instance() { return instance.get(); }

    nova_renderer* nova_renderer::initialize(const settings_options& settings) {
        return (instance = std::make_unique<nova_renderer>(settings)).get();
    }

    void nova_renderer::deinitialize() { instance = nullptr; }

    nova::ttl::task_scheduler& nova_renderer::get_task_scheduler() { return task_scheduler; }
} // namespace nova::renderer
<|endoftext|>


<commit_before>#include "mud.h"
#include "conf.h"
#include "objectManager.h"
#include "baseObject.h"
#include "staticObject.h"
#include "entity.h"
#include "npc.h"
#include "room.h"
#include "world.h"

ObjectManager::ObjectManager()
{
}
ObjectManager::~ObjectManager()
{
}

void ObjectManager::Update()
{
    for (auto npc: _npcs)
        {
            (npc.second)->Update();
        }
}
Entity* ObjectManager::CreateObject(VNUM obj)
{
    Entity* object = NULL;
    StaticObject* virt = NULL;
    World* world = World::GetPtr();

    if (obj != 0 && !VirtualExists(obj))
        {
            world->WriteLog("Tried to create virtual with nonexistant vnum", ERR);
            return NULL;
        }

    virt = _objects[obj];
    object = virt->Create();
    return object;
}
BOOL ObjectManager::RecycleObject(ObjectContainer* obj)
{
    World* world = World::GetPtr();
    ObjectContainer* location = NULL;
    StaticObject* vobj = NULL;

    if(!obj)
        {
            return false;
        }

//we recursively recycle everything in contents.
    std::list<Entity*>::iterator it, itEnd;
    std::list<Entity*>* contents = obj->GetContents();

//recursively delete objects held by the object being deleted.
    itEnd = contents->end();
    for (it = contents->begin(); it != itEnd; ++it)
        {
            RecycleObject((*it));
        }

//check to see if this object is stored in another. If so, we need to remove it.

    if (obj->IsObject())
        {
            location = ((Entity*)obj)->GetLocation();
            if (location)
                {
                    location->ObjectLeave((Entity*)obj);
                }

//recycle this instance with it's virtual object, if there is one.
            if (obj->GetOnum())
                {
                    vobj = GetVirtual(((Entity*)obj)->GetOnum());
                    if (vobj)
                        {
                            vobj->Recycle((Entity*)obj);
                        }
                }
        }

    world->events.CallEvent("ObjectDestroyed", NULL, (void*)obj);
    delete obj;
    return true;
}

BOOL ObjectManager::AddVirtual(StaticObject* obj)
{
    VNUM num = 0;
    if (!obj)
        {
            return false;
        }

    num = obj->GetOnum();
    if (VirtualExists(num))
        {
            return false;
        }

    _objects[num] = obj;
    return true;
}
BOOL ObjectManager::VirtualExists(VNUM num)
{
    return (_objects.count(num)? true:false);
}
StaticObject* ObjectManager::GetVirtual(VNUM num)
{
    if (!VirtualExists(num))
        {
            return NULL;
        }

    return _objects[num];
}
BOOL ObjectManager::RemoveVirtual(VNUM num)
{
    StaticObject* virt = GetVirtual(num);
    if (!virt)
        {
            return false;
        }

    virt->RecycleContents();
    _objects.erase(num);
    return true;
}
VNUM ObjectManager::GetFreeVirtualVnum(VNUM min, VNUM max, VNUM num)
{
    int i = min;
    if (!num)
        {
            return (VirtualExists(num) ? num : 0);
        }

    for (; i <= max; ++i)
        {
            if (!VirtualExists(i))
                {
                    return i;
                }
        }

    return 0;
}

BOOL ObjectManager::AddRoom(Room* room)
{
    VNUM num = 0;
    if (!room)
        {
            return false;
        }

    num = room->GetOnum();
    if (RoomExists(num))
        {
            return false;
        }

    _rooms[num] = room;
    return true;
}
BOOL ObjectManager::RemoveRoom(VNUM num)
{
    Room* room = NULL;

    room = GetRoom(num);
    if (!room)
        {
            return false;
        }

    _rooms.erase(room->GetOnum());
    return true;
}
BOOL ObjectManager::RoomExists(VNUM num)
{
    return _rooms.count(num)? true : false;
}
Room* ObjectManager::GetRoom(VNUM num)
{
    if (!RoomExists(num))
        {
            return NULL;
        }

    return _rooms[num];
}
VNUM ObjectManager::GetFreeRoomVnum(VNUM min, VNUM max, VNUM num)
{
    int i = min;
    if (!num)
        {
            return (RoomExists(num) ? num : 0);
        }

    for (; i <= max; ++i)
        {
            if (!RoomExists(i))
                {
                    return i;
                }
        }

    return 0;
}

BOOL ObjectManager::AddNpc(Npc* mob)
{
    VNUM num = 0;

    if (!mob)
        {
            return false;
        }

    num = mob->GetOnum();
    if (NpcExists(num))
        {
            return false;
        }

    _npcs[num] = mob;
    return true;
}
BOOL ObjectManager::RemoveNpc(VNUM num)
{
    Npc* mob = NULL;

    mob = GetNpc(num);
    if (!mob)
        {
            return false;
        }

    _npcs.erase(mob->GetOnum());
    return true;
}
bool ObjectManager::NpcExists(VNUM num)
{
    return  (_npcs.count(num) ? true : false);
}
Npc*  ObjectManager::GetNpc(VNUM num)
{
    if (!NpcExists(num))
        {
            return NULL;
        }

    return _npcs[num];
}
VNUM ObjectManager::GetFreeNpcVnum(VNUM min, VNUM max, VNUM num)
{
    int i = min;
    if (!num)
        {
            return (NpcExists(num) ? num : 0);
        }

    for (; i <= max; ++i)
        {
            if (!NpcExists(i))
                {
                    return i;
                }
        }

    return 0;
}
<commit_msg>Fixed vcreate logic<commit_after>#include "mud.h"
#include "conf.h"
#include "objectManager.h"
#include "baseObject.h"
#include "staticObject.h"
#include "entity.h"
#include "npc.h"
#include "room.h"
#include "world.h"

ObjectManager::ObjectManager()
{
}
ObjectManager::~ObjectManager()
{
}

void ObjectManager::Update()
{
    for (auto npc: _npcs)
        {
            (npc.second)->Update();
        }
}
Entity* ObjectManager::CreateObject(VNUM obj)
{
    Entity* object = NULL;
    StaticObject* virt = NULL;
    World* world = World::GetPtr();

    if (obj != 0 && !VirtualExists(obj))
        {
            world->WriteLog("Tried to create virtual with nonexistant vnum", ERR);
            return NULL;
        }

    virt = _objects[obj];
    object = virt->Create();
    return object;
}
BOOL ObjectManager::RecycleObject(ObjectContainer* obj)
{
    World* world = World::GetPtr();
    ObjectContainer* location = NULL;
    StaticObject* vobj = NULL;

    if(!obj)
        {
            return false;
        }

//we recursively recycle everything in contents.
    std::list<Entity*>::iterator it, itEnd;
    std::list<Entity*>* contents = obj->GetContents();

//recursively delete objects held by the object being deleted.
    itEnd = contents->end();
    for (it = contents->begin(); it != itEnd; ++it)
        {
            RecycleObject((*it));
        }

//check to see if this object is stored in another. If so, we need to remove it.

    if (obj->IsObject())
        {
            location = ((Entity*)obj)->GetLocation();
            if (location)
                {
                    location->ObjectLeave((Entity*)obj);
                }

//recycle this instance with it's virtual object, if there is one.
            if (obj->GetOnum())
                {
                    vobj = GetVirtual(((Entity*)obj)->GetOnum());
                    if (vobj)
                        {
                            vobj->Recycle((Entity*)obj);
                        }
                }
        }

    world->events.CallEvent("ObjectDestroyed", NULL, (void*)obj);
    delete obj;
    return true;
}

BOOL ObjectManager::AddVirtual(StaticObject* obj)
{
    VNUM num = 0;
    if (!obj)
        {
            return false;
        }

    num = obj->GetOnum();
    if (VirtualExists(num))
        {
            return false;
        }

    _objects[num] = obj;
    return true;
}
BOOL ObjectManager::VirtualExists(VNUM num)
{
    return (_objects.count(num)? true:false);
}
StaticObject* ObjectManager::GetVirtual(VNUM num)
{
    if (!VirtualExists(num))
        {
            return NULL;
        }

    return _objects[num];
}
BOOL ObjectManager::RemoveVirtual(VNUM num)
{
    StaticObject* virt = GetVirtual(num);
    if (!virt)
        {
            return false;
        }

    virt->RecycleContents();
    _objects.erase(num);
    return true;
}
VNUM ObjectManager::GetFreeVirtualVnum(VNUM min, VNUM max, VNUM num)
{
    int i = min;
    if (num != 0)
        {
            return (!VirtualExists(num) ? num : 0);
        }

    for (; i <= max; ++i)
        {
            if (!VirtualExists(i))
                {
                    return i;
                }
        }

    return 0;
}

BOOL ObjectManager::AddRoom(Room* room)
{
    VNUM num = 0;
    if (!room)
        {
            return false;
        }

    num = room->GetOnum();
    if (RoomExists(num))
        {
            return false;
        }

    _rooms[num] = room;
    return true;
}
BOOL ObjectManager::RemoveRoom(VNUM num)
{
    Room* room = NULL;

    room = GetRoom(num);
    if (!room)
        {
            return false;
        }

    _rooms.erase(room->GetOnum());
    return true;
}
BOOL ObjectManager::RoomExists(VNUM num)
{
    return _rooms.count(num)? true : false;
}
Room* ObjectManager::GetRoom(VNUM num)
{
    if (!RoomExists(num))
        {
            return NULL;
        }

    return _rooms[num];
}
VNUM ObjectManager::GetFreeRoomVnum(VNUM min, VNUM max, VNUM num)
{
    int i = min;
    if (!num)
        {
            return (RoomExists(num) ? num : 0);
        }

    for (; i <= max; ++i)
        {
            if (!RoomExists(i))
                {
                    return i;
                }
        }

    return 0;
}

BOOL ObjectManager::AddNpc(Npc* mob)
{
    VNUM num = 0;

    if (!mob)
        {
            return false;
        }

    num = mob->GetOnum();
    if (NpcExists(num))
        {
            return false;
        }

    _npcs[num] = mob;
    return true;
}
BOOL ObjectManager::RemoveNpc(VNUM num)
{
    Npc* mob = NULL;

    mob = GetNpc(num);
    if (!mob)
        {
            return false;
        }

    _npcs.erase(mob->GetOnum());
    return true;
}
bool ObjectManager::NpcExists(VNUM num)
{
    return  (_npcs.count(num) ? true : false);
}
Npc*  ObjectManager::GetNpc(VNUM num)
{
    if (!NpcExists(num))
        {
            return NULL;
        }

    return _npcs[num];
}
VNUM ObjectManager::GetFreeNpcVnum(VNUM min, VNUM max, VNUM num)
{
    int i = min;
    if (!num)
        {
            return (NpcExists(num) ? num : 0);
        }

    for (; i <= max; ++i)
        {
            if (!NpcExists(i))
                {
                    return i;
                }
        }

    return 0;
}
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Definition of pulse object
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#ifndef ALLPIX_PULSE_H
#define ALLPIX_PULSE_H

#include <vector>

#include <TObject.h>

namespace allpix {
    /**
     * @ingroup Objects
     * @brief Pulse holding induced charges as a function of time
     * @warning This object is special and is not meant to be written directly to a tree (not inheriting from \ref Object)
     */
    class Pulse {
    public:
        /**
         * @brief Construct a new pulse
         */
        Pulse(double time_bin);

        /**
         * @brief Construct default pulse, uninitialized
         */
        Pulse() = default;

        /**
         * @brief adding induced charge to the pulse
         * @param charge induced charge
         * @param time   time when it has been induced
         */
        void addCharge(double charge, double time);

        /**
         * @brief Function to retrieve the integral (net) charge from the full pulse
         * @return Integrated charge
         */
        int getCharge() const;

        /**
         * @brief Function to retrieve the full pulse shape
         * @return Constant reference to the pulse vector
         */
        const std::vector<double>& getPulse() const;

        /**
         * @brief Function to retrieve time binning of pulse
         * @return Width of one pulse bin in nanoseconds
         */
        double getBinning() const;

        /**
         * @brief compound assignment operator to sum different pulses
         * @throws IncompatibleDatatypesException If the binning of the pulses does not match
         */
        Pulse& operator+=(const Pulse& rhs);

        /**
         * @brief Default constructor for ROOT I/O
         */
        ClassDef(Pulse, 2);

    private:
        std::vector<double> pulse_;
        double bin_;
        bool initialized_{};
    };

} // namespace allpix

#endif
<commit_msg>Pulse: make constructor explicit<commit_after>/**
 * @file
 * @brief Definition of pulse object
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#ifndef ALLPIX_PULSE_H
#define ALLPIX_PULSE_H

#include <vector>

#include <TObject.h>

namespace allpix {
    /**
     * @ingroup Objects
     * @brief Pulse holding induced charges as a function of time
     * @warning This object is special and is not meant to be written directly to a tree (not inheriting from \ref Object)
     */
    class Pulse {
    public:
        /**
         * @brief Construct a new pulse
         */
        explicit Pulse(double time_bin);

        /**
         * @brief Construct default pulse, uninitialized
         */
        Pulse() = default;

        /**
         * @brief adding induced charge to the pulse
         * @param charge induced charge
         * @param time   time when it has been induced
         */
        void addCharge(double charge, double time);

        /**
         * @brief Function to retrieve the integral (net) charge from the full pulse
         * @return Integrated charge
         */
        int getCharge() const;

        /**
         * @brief Function to retrieve the full pulse shape
         * @return Constant reference to the pulse vector
         */
        const std::vector<double>& getPulse() const;

        /**
         * @brief Function to retrieve time binning of pulse
         * @return Width of one pulse bin in nanoseconds
         */
        double getBinning() const;

        /**
         * @brief compound assignment operator to sum different pulses
         * @throws IncompatibleDatatypesException If the binning of the pulses does not match
         */
        Pulse& operator+=(const Pulse& rhs);

        /**
         * @brief Default constructor for ROOT I/O
         */
        ClassDef(Pulse, 2);

    private:
        std::vector<double> pulse_;
        double bin_;
        bool initialized_{};
    };

} // namespace allpix

#endif
<|endoftext|>


<commit_before>//
//  ofxApplePlist.cpp
//
//  Maintained and open sourced by
//
//  Hans Bijkerk, datishans.nl, twitter.com/datishans
//
#include "ofxApplePlist.h"

Poco::Any ofxApplePlist::load(ofFile file) {
    ofBuffer buffer = file.readToBuffer();
    plist.loadFromBuffer(buffer.getText());
    plist.setTo("plist");
    plist.setToChild(0);

    return toAny();
}

Poco::Any ofxApplePlist::load(string plistdata) {
    plist.loadFromBuffer(plistdata);
    plist.setTo("plist");
    plist.setToChild(0);

    return toAny();
}

Poco::Any ofxApplePlist::toAny() {

    if (plist.getName() == "dict") {
        std::map<string, Poco::Any> dict;
        string currentKey = "";
        plist.setToChild(0);

        while(1) {
            currentKey = "";
            if (plist.getName() == "key") {
                currentKey = plist.getValue();
                //ofLogNotice(""," - key %s", currentKey.c_str());
            }
            if (currentKey == "") {
                break;
            }

            // to corresponding value
            plist.setToSibling();
            Poco::Any value = toAny();
            dict[currentKey] = value;

            // to next key
            plist.setToSibling();
        }

        // step out of dict
        plist.setToParent();

        return dict;
    }

    if (plist.getName() == "array") {
        vector<Poco::Any> arr;
        int numChildren = plist.getNumChildren();

        if (numChildren > 0) {
            plist.setToChild(0);

            for (int n = 0; n < numChildren; n++) {
                Poco::Any value = toAny();
                arr.push_back(value);

                // to next value
                plist.setToSibling();
            }

            // step out of array
            plist.setToParent();
        }

        return arr;
    }

    if (plist.getName() == "true") {
        return true;
    }
    if (plist.getName() == "true") {
        return false;
    }
    if (plist.getName() == "string") {
        return plist.getValue();
    }
    if (plist.getName() == "integer") {
        return stol(plist.getValue());
    }

    ofLog(OF_LOG_WARNING, "plist type %s not supported!", plist.getValue().c_str());

    return NULL;
}
<commit_msg>boolean "true" returned "false".<commit_after>//
//  ofxApplePlist.cpp
//
//  Maintained and open sourced by
//
//  Hans Bijkerk, datishans.nl, twitter.com/datishans
//
#include "ofxApplePlist.h"

Poco::Any ofxApplePlist::load(ofFile file) {
    ofBuffer buffer = file.readToBuffer();
    plist.loadFromBuffer(buffer.getText());
    plist.setTo("plist");
    plist.setToChild(0);

    return toAny();
}

Poco::Any ofxApplePlist::load(string plistdata) {
    plist.loadFromBuffer(plistdata);
    plist.setTo("plist");
    plist.setToChild(0);

    return toAny();
}

Poco::Any ofxApplePlist::toAny() {

    if (plist.getName() == "dict") {
        std::map<string, Poco::Any> dict;
        string currentKey = "";
        plist.setToChild(0);

        while(1) {
            currentKey = "";
            if (plist.getName() == "key") {
                currentKey = plist.getValue();
                //ofLogNotice(""," - key %s", currentKey.c_str());
            }
            if (currentKey == "") {
                break;
            }

            // to corresponding value
            plist.setToSibling();
            Poco::Any value = toAny();
            dict[currentKey] = value;

            // to next key
            plist.setToSibling();
        }

        // step out of dict
        plist.setToParent();

        return dict;
    }

    if (plist.getName() == "array") {
        vector<Poco::Any> arr;
        int numChildren = plist.getNumChildren();

        if (numChildren > 0) {
            plist.setToChild(0);

            for (int n = 0; n < numChildren; n++) {
                Poco::Any value = toAny();
                arr.push_back(value);

                // to next value
                plist.setToSibling();
            }

            // step out of array
            plist.setToParent();
        }

        return arr;
    }

    if (plist.getName() == "true") {
        return true;
    }
    if (plist.getName() == "false") {
        return false;
    }
    if (plist.getName() == "string") {
        return plist.getValue();
    }
    if (plist.getName() == "integer") {
        return stol(plist.getValue());
    }

    ofLog(OF_LOG_WARNING, "plist type %s not supported!", plist.getValue().c_str());

    return false;
}
<|endoftext|>


<commit_before>#include "builtins.hpp"

namespace lang {
  OperatorMap opsMap = {
    {Operator("+", 10), {
      {"Integer Integer", boost::any(new Object::BinaryOp([](Object* l, Object* r) {
        Integer* left = dynamic_cast<Integer*>(l);
        Integer* right = dynamic_cast<Integer*>(r);
        return new Integer(left->getNumber() + right->getNumber());
      }))},
      {"Float Float", boost::any(new Object::BinaryOp([](Object* l, Object* r) {
        Float* left = dynamic_cast<Float*>(l);
        Float* right = dynamic_cast<Float*>(r);
        return new Float(left->getNumber() + right->getNumber());
      }))}
    }},
    {Operator("-", 10), {
      {"Integer Integer", boost::any(new Object::BinaryOp([](Object* l, Object* r) {
        Integer* left = dynamic_cast<Integer*>(l);
        Integer* right = dynamic_cast<Integer*>(r);
        return new Integer(left->getNumber() - right->getNumber());
      }))},
      {"Float Float", boost::any(new Object::BinaryOp([](Object* l, Object* r) {
        Float* left = dynamic_cast<Float*>(l);
        Float* right = dynamic_cast<Float*>(r);
        return new Float(left->getNumber() - right->getNumber());
      }))}
    }},
  };
} /* namespace lang */<commit_msg>Added more operator maps<commit_after>#include "builtins.hpp"

namespace lang {
  OperatorMap opsMap = {
    {Operator("+", 10), {
      {"String String", boost::any(new Object::BinaryOp([](Object* l, Object* r) {
        auto left = dynamic_cast<String*>(l);
        auto right = dynamic_cast<String*>(r);
        return new String(left->toString() + right->toString());
      }))},
      {"Integer Integer", boost::any(new Object::BinaryOp([](Object* l, Object* r) {
        Integer* left = dynamic_cast<Integer*>(l);
        Integer* right = dynamic_cast<Integer*>(r);
        return new Integer(left->getNumber() + right->getNumber());
      }))},
      {"Float Float", boost::any(new Object::BinaryOp([](Object* l, Object* r) {
        Float* left = dynamic_cast<Float*>(l);
        Float* right = dynamic_cast<Float*>(r);
        return new Float(left->getNumber() + right->getNumber());
      }))},
      {"Integer Float", boost::any(new Object::BinaryOp([](Object* l, Object* r) {
        Integer* left = dynamic_cast<Integer*>(l);
        Float* right = dynamic_cast<Float*>(r);
        return new Float(left->getNumber() + right->getNumber());
      }))},
      {"Float Integer", boost::any(new Object::BinaryOp([](Object* l, Object* r) {
        Float* left = dynamic_cast<Float*>(l);
        Integer* right = dynamic_cast<Integer*>(r);
        return new Float(left->getNumber() + right->getNumber());
      }))}
    }},
    {Operator("-", 10), {
      {"Integer Integer", boost::any(new Object::BinaryOp([](Object* l, Object* r) {
        Integer* left = dynamic_cast<Integer*>(l);
        Integer* right = dynamic_cast<Integer*>(r);
        return new Integer(left->getNumber() - right->getNumber());
      }))},
      {"Float Float", boost::any(new Object::BinaryOp([](Object* l, Object* r) {
        Float* left = dynamic_cast<Float*>(l);
        Float* right = dynamic_cast<Float*>(r);
        return new Float(left->getNumber() - right->getNumber());
      }))}
    }},
  };
} /* namespace lang */<|endoftext|>


<commit_before>/// \file uparser.cc

//#define ENABLE_DEBUG_TRACES
#include "libport/compiler.hh"

#include <cstdlib>
#include <cassert>

#include <sstream>
#include <strstream>
#include <fstream>
#include <algorithm>
#include <string>

#include <libport/foreach.hh>

#include "server-timer.hh"
#include "uparser.hh"
#include "ast/nary.hh"

/*----------.
| UParser.  |
`----------*/

UParser::UParser()
  : ast_ (0),
    errors_ (),
    warnings_ (),
    scanner_ (),
    loc_()
{
  // The first column for locations is 1.
  loc_.begin.column = loc_.end.column = 1;
}

int
UParser::parse_ ()
{
  TIMER_PUSH("parse");
  ast_ = 0;

  parser_type p(*this);
#ifdef ENABLE_DEBUG_TRACES
  p.set_debug_level(true);
#else
  p.set_debug_level (!!getenv ("YYDEBUG"));
#endif
  ECHO("====================== Parse begin");
  int res = p.parse();
  ECHO("====================== Parse end: " << res);
  TIMER_POP("parse");
  return res;
}

int
UParser::process (const std::string& command)
{
  // It has been said Flex scanners cannot work with istrstream.
  std::istrstream mem_buff (command.c_str ());
  std::istream mem_input (mem_buff.rdbuf());
  scanner_.switch_streams(&mem_input, 0);
  ECHO("Parsing string: ==================\n"
       << loc_ << ":\n" << command
       << "\n==================================");
  return parse_ ();
}

ast::Ast*
UParser::ast_get ()
{
  if (hasError ())
    return 0;
  return ast_;
}

const ast::Ast*
UParser::ast_get () const
{
  if (hasError ())
    return 0;
  return ast_;
}

void
UParser::ast_set (ast::Ast* ast)
{
  ast_ = ast;
}

int
UParser::process_file (const std::string& fn)
{
  // A location pointing to it.
  location_type loc;
  loc.initialize (new libport::Symbol(fn));
  // The convention for the first column changed: make sure the first
  // column is column 1.
  loc.begin.column = loc.end.column = 1;

  // Exchange with the current location so that we can restore it
  // afterwards (when reading the input flow, we want to be able to
  // restore the cursor after having handled a load command).
  std::swap(loc, loc_);
  std::ifstream f (fn.c_str());
  if (!f.good())
    return 1; // Return an error instead of creating a valid empty ast.
  scanner_.switch_streams(&f, 0);
  ECHO("Parsing file: " << fn);
  int res = parse_();
  std::swap(loc, loc_);
  return res;
}

void
UParser::message_push(messages_type& msgs,
		      const yy::parser::location_type& l,
		      const std::string& msg)
{
  std::ostringstream o;
  o << "!!! " << l << ": " << msg;
  msgs.push_back(o.str());
}

void
UParser::process_errors(ast::Nary* target)
{
  foreach(std::string e, warnings_)
    target->message_push(e, "warning");
  warnings_.clear();

  // Errors handling
  if (!errors_.empty())
  {
    delete ast_;
    ast_ = 0;

    foreach(std::string e, errors_)
      target->message_push(e, "error");
    errors_.clear();
  }
}

void
UParser::error (const yy::parser::location_type& l, const std::string& msg)
{
  message_push(errors_, l, msg);
}

void
UParser::warn (const yy::parser::location_type& l, const std::string& msg)
{
  message_push(warnings_, l, msg);
}

bool
UParser::hasError () const
{
  return !errors_.empty();
}

std::string
UParser::error_get () const
{
  // precondition
  assert(hasError());
  return errors_.front();
}

bool
UParser::hasWarning () const
{
  return !warnings_.empty();
}

std::string
UParser::warning_get () const
{
  // precondition
  assert(hasWarning());
  return warnings_.front();
}

void
UParser::warning_pop ()
{
  warnings_.pop_front();
}

void
UParser::error_pop ()
{
  errors_.pop_front();
}
<commit_msg>Iterate with references<commit_after>/// \file uparser.cc

//#define ENABLE_DEBUG_TRACES
#include "libport/compiler.hh"

#include <cstdlib>
#include <cassert>

#include <sstream>
#include <strstream>
#include <fstream>
#include <algorithm>
#include <string>

#include <libport/foreach.hh>

#include "server-timer.hh"
#include "uparser.hh"
#include "ast/nary.hh"

/*----------.
| UParser.  |
`----------*/

UParser::UParser()
  : ast_ (0),
    errors_ (),
    warnings_ (),
    scanner_ (),
    loc_()
{
  // The first column for locations is 1.
  loc_.begin.column = loc_.end.column = 1;
}

int
UParser::parse_ ()
{
  TIMER_PUSH("parse");
  ast_ = 0;

  parser_type p(*this);
#ifdef ENABLE_DEBUG_TRACES
  p.set_debug_level(true);
#else
  p.set_debug_level (!!getenv ("YYDEBUG"));
#endif
  ECHO("====================== Parse begin");
  int res = p.parse();
  ECHO("====================== Parse end: " << res);
  TIMER_POP("parse");
  return res;
}

int
UParser::process (const std::string& command)
{
  // It has been said Flex scanners cannot work with istrstream.
  std::istrstream mem_buff (command.c_str ());
  std::istream mem_input (mem_buff.rdbuf());
  scanner_.switch_streams(&mem_input, 0);
  ECHO("Parsing string: ==================\n"
       << loc_ << ":\n" << command
       << "\n==================================");
  return parse_ ();
}

ast::Ast*
UParser::ast_get ()
{
  if (hasError ())
    return 0;
  return ast_;
}

const ast::Ast*
UParser::ast_get () const
{
  if (hasError ())
    return 0;
  return ast_;
}

void
UParser::ast_set (ast::Ast* ast)
{
  ast_ = ast;
}

int
UParser::process_file (const std::string& fn)
{
  // A location pointing to it.
  location_type loc;
  loc.initialize (new libport::Symbol(fn));
  // The convention for the first column changed: make sure the first
  // column is column 1.
  loc.begin.column = loc.end.column = 1;

  // Exchange with the current location so that we can restore it
  // afterwards (when reading the input flow, we want to be able to
  // restore the cursor after having handled a load command).
  std::swap(loc, loc_);
  std::ifstream f (fn.c_str());
  if (!f.good())
    return 1; // Return an error instead of creating a valid empty ast.
  scanner_.switch_streams(&f, 0);
  ECHO("Parsing file: " << fn);
  int res = parse_();
  std::swap(loc, loc_);
  return res;
}

void
UParser::message_push(messages_type& msgs,
		      const yy::parser::location_type& l,
		      const std::string& msg)
{
  std::ostringstream o;
  o << "!!! " << l << ": " << msg;
  msgs.push_back(o.str());
}

void
UParser::process_errors(ast::Nary* target)
{
  foreach(const std::string& e, warnings_)
    target->message_push(e, "warning");
  warnings_.clear();

  // Errors handling
  if (!errors_.empty())
  {
    delete ast_;
    ast_ = 0;

    foreach(const std::string& e, errors_)
      target->message_push(e, "error");
    errors_.clear();
  }
}

void
UParser::error (const yy::parser::location_type& l, const std::string& msg)
{
  message_push(errors_, l, msg);
}

void
UParser::warn (const yy::parser::location_type& l, const std::string& msg)
{
  message_push(warnings_, l, msg);
}

bool
UParser::hasError () const
{
  return !errors_.empty();
}

std::string
UParser::error_get () const
{
  // precondition
  assert(hasError());
  return errors_.front();
}

bool
UParser::hasWarning () const
{
  return !warnings_.empty();
}

std::string
UParser::warning_get () const
{
  // precondition
  assert(hasWarning());
  return warnings_.front();
}

void
UParser::warning_pop ()
{
  warnings_.pop_front();
}

void
UParser::error_pop ()
{
  errors_.pop_front();
}
<|endoftext|>


<commit_before>/*=========================================================================

 Program: FEMUS
 Module: Solid
 Authors: Simone Bnà

 Copyright (c) FEMTTU
 All rights reserved.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

//----------------------------------------------------------------------------
// includes :
//----------------------------------------------------------------------------
#include "Solid.hpp"
#include "Material.hpp"
#include "iostream"
#include "cstdlib"
#include "cstring"
#include "Parameter.hpp"

namespace femus {

using namespace std;

Solid::Solid() : Material() {
  _young_module = 1.;
  _poisson_coeff = 0.3;
  _lambda_lame = 1.;
  _mu_lame  = 1.;
  _model = 0;
}

Solid::Solid(Parameter& par) : Material(par) {
  _young_module = 1.;
  _poisson_coeff = 0.3;
  _lambda_lame = 1.;
  _mu_lame  = 1.;
  _model = 0;
}

Solid::Solid(Parameter& par, const double young_module, const double poisson_coeff,
             const double density, const char model[],
             const double k, const double cp, const double alpha) : Material(par,density,k,cp,alpha) {
  _young_module = young_module;

  if (!strcmp(model,"Linear_elastic") || !strcmp(model,"Saint-Venant")) {
    _model = 0;
    _penalty = false;
    _mass_penalty=false;
  }
  if (!strcmp(model,"Saint-Venant-Penalty")) {
    _model = 0;
    _penalty = true;
    _mass_penalty=false;
  }
  else if (!strcmp(model,"Neo-Hookean") || !strcmp(model,"Neo-Hookean-MassPenalty")) {
    _model = 1;
    _penalty = false;
    _mass_penalty=!strcmp(model,"Neo-Hookean-MassPenalty")?true:false;
  }
  else if (!strcmp(model,"Neo-Hookean-BW") || !strcmp(model,"Neo-Hookean-BW-MassPenalty") ) {
    _model = 2;
    _penalty = false;
    _mass_penalty=!strcmp(model,"Neo-Hookean-BW-MassPenalty")?true:false;
  }
  else if (!strcmp(model,"Neo-Hookean-BW-Penalty")) {
    _model = 3;
    _penalty = true;
    _mass_penalty=false;
  }
  else if (!strcmp(model,"Neo-Hookean-AB-Penalty")) {
    _model = 4;
    _penalty = true;
    _mass_penalty = false;
  }
   else if (!strcmp(model,"Mooney-Rivlin") || !strcmp(model,"Mooney-Rivlin-MassPenalty")) {
    _model = 5;
    _penalty = false;
    _mass_penalty=(!strcmp(model,"Mooney-Rivlin-MassPenalty"))?true:false;
  }
  else {
    cout<<"Error! This solid model is not implemented "<<endl;
    exit(1);
  }

  if (poisson_coeff <= 0.5 && poisson_coeff >= 0) {
    _poisson_coeff = poisson_coeff;
  }
  else {
    cout << "Error: the value for the Poisson coeffcient must be greater than 0 and less equal than 0.5!" << endl;
    exit(1);
  }

  if(poisson_coeff<0.5){
    _lambda_lame = (_young_module*_poisson_coeff)/((1.+_poisson_coeff)*(1.-2.*_poisson_coeff));
  }
  else if (true == _penalty){
    std::cout<<"Error this solid model requires a Poisson coeffcient strictly less than 0.5"<<endl;
    exit(1);
  }
  else{
    cout << "Warning: the value for the Poisson coeffcient is 0.5, the material is incompressible"<<endl
	 << "The Lame constant is infinity and it has been set equal to 1.0e100" << endl;
    _lambda_lame =1.0e100;
  }
  _mu_lame     = _young_module/(2.*(1.+_poisson_coeff));

//   cout << endl << "SOLID properties: " << endl;
//   cout << "Density [kg/m3]: " << _density << endl;
//   cout << "Young Module [Pa/m2]: " << _young_module << endl;
//   cout << "Poisson Coefficient: " << _poisson_coeff << endl;
//   cout << "Lambda (Lame first parameter): " << _lambda_lame << endl;
//   cout << "Shear Modulus (Lame second parameter): " << _mu_lame <<  endl << endl;

}

void Solid::set_young_module(const double young_module) {
  _young_module = young_module;
}

void Solid::set_poisson_coeff(const double poisson_coeff) {
  _poisson_coeff = poisson_coeff;
}

const unsigned Solid::get_physical_model() const{
  return _model;
}

const double Solid::get_young_module() const{
  return _young_module;
}

const double Solid::get_poisson_coeff() const{
  return _poisson_coeff;
}

const double Solid::get_lame_lambda() const{
  return _lambda_lame;
}

const double Solid::get_lame_shear_modulus() const{
  return _mu_lame;
}

const bool Solid::get_if_penalty() const{
  return _penalty;
}

const bool Solid::get_if_mass_penalty() const{
  return _mass_penalty;
}

std::ostream & operator << (std::ostream & os, const Solid & solid)
{
  os << "Density: " << solid._density << std::endl;
  os << "Young Module: " << solid._young_module << std::endl;
  os << "Poisson coeffcient: " << solid._poisson_coeff << std::endl;
  os << "Lambda Lamé: " << solid._lambda_lame << std::endl;
  os << "Mu lamé: " << solid._mu_lame << std::endl;
  os << "Physical Model: " << solid._model << std::endl;
  os << std::endl;
  return os;
}

// Take a const-reference to the right-hand side of the assignment.
// Return a non-const reference to the left-hand side.
Solid& Solid::operator=(const Solid &solid) {
  this->_parameter 			= solid._parameter;
  this->_density 			= solid._density;
  this->_thermal_conductivity 		= solid._thermal_conductivity;
  this->_heat_capacity 			= solid._heat_capacity;
  this->_thermal_expansion_coefficient 	= solid._thermal_expansion_coefficient;
  this->_young_module 			= solid._young_module;
  this->_poisson_coeff 			= solid._poisson_coeff;
  this->_lambda_lame 			= solid._lambda_lame;
  this->_mu_lame 			= solid._mu_lame;
  this->_model 				= solid._model;
  this->_penalty 			= solid._penalty;
  this->_mass_penalty 			= solid._mass_penalty;
  return *this;  // Return a reference to myself.
}

} //end namespace femus

<commit_msg>Fixed an error in the if loop<commit_after>/*=========================================================================

 Program: FEMUS
 Module: Solid
 Authors: Simone Bnà

 Copyright (c) FEMTTU
 All rights reserved.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

//----------------------------------------------------------------------------
// includes :
//----------------------------------------------------------------------------
#include "Solid.hpp"
#include "Material.hpp"
#include "iostream"
#include "cstdlib"
#include "cstring"
#include "Parameter.hpp"

namespace femus {

using namespace std;

Solid::Solid() : Material() {
  _young_module = 1.;
  _poisson_coeff = 0.3;
  _lambda_lame = 1.;
  _mu_lame  = 1.;
  _model = 0;
}

Solid::Solid(Parameter& par) : Material(par) {
  _young_module = 1.;
  _poisson_coeff = 0.3;
  _lambda_lame = 1.;
  _mu_lame  = 1.;
  _model = 0;
}

Solid::Solid(Parameter& par, const double young_module, const double poisson_coeff,
             const double density, const char model[],
             const double k, const double cp, const double alpha) : Material(par,density,k,cp,alpha) {
  _young_module = young_module;

  if (!strcmp(model,"Linear_elastic") || !strcmp(model,"Saint-Venant")) {
    _model = 0;
    _penalty = false;
    _mass_penalty=false;
  }
  else if (!strcmp(model,"Saint-Venant-Penalty")) {
    _model = 0;
    _penalty = true;
    _mass_penalty=false;
  }
  else if (!strcmp(model,"Neo-Hookean") || !strcmp(model,"Neo-Hookean-MassPenalty")) {
    _model = 1;
    _penalty = false;
    _mass_penalty=!strcmp(model,"Neo-Hookean-MassPenalty")?true:false;
  }
  else if (!strcmp(model,"Neo-Hookean-BW") || !strcmp(model,"Neo-Hookean-BW-MassPenalty") ) {
    _model = 2;
    _penalty = false;
    _mass_penalty=!strcmp(model,"Neo-Hookean-BW-MassPenalty")?true:false;
  }
  else if (!strcmp(model,"Neo-Hookean-BW-Penalty")) {
    _model = 3;
    _penalty = true;
    _mass_penalty=false;
  }
  else if (!strcmp(model,"Neo-Hookean-AB-Penalty")) {
    _model = 4;
    _penalty = true;
    _mass_penalty = false;
  }
   else if (!strcmp(model,"Mooney-Rivlin") || !strcmp(model,"Mooney-Rivlin-MassPenalty")) {
    _model = 5;
    _penalty = false;
    _mass_penalty=(!strcmp(model,"Mooney-Rivlin-MassPenalty"))?true:false;
  }
  else {
    cout<<"Error! This solid model is not implemented "<<endl;
    exit(1);
  }

  if (poisson_coeff <= 0.5 && poisson_coeff >= 0) {
    _poisson_coeff = poisson_coeff;
  }
  else {
    cout << "Error: the value for the Poisson coeffcient must be greater than 0 and less equal than 0.5!" << endl;
    exit(1);
  }

  if(poisson_coeff<0.5){
    _lambda_lame = (_young_module*_poisson_coeff)/((1.+_poisson_coeff)*(1.-2.*_poisson_coeff));
  }
  else if (true == _penalty){
    std::cout<<"Error this solid model requires a Poisson coeffcient strictly less than 0.5"<<endl;
    exit(1);
  }
  else{
    cout << "Warning: the value for the Poisson coeffcient is 0.5, the material is incompressible"<<endl
	 << "The Lame constant is infinity and it has been set equal to 1.0e100" << endl;
    _lambda_lame =1.0e100;
  }
  _mu_lame     = _young_module/(2.*(1.+_poisson_coeff));

//   cout << endl << "SOLID properties: " << endl;
//   cout << "Density [kg/m3]: " << _density << endl;
//   cout << "Young Module [Pa/m2]: " << _young_module << endl;
//   cout << "Poisson Coefficient: " << _poisson_coeff << endl;
//   cout << "Lambda (Lame first parameter): " << _lambda_lame << endl;
//   cout << "Shear Modulus (Lame second parameter): " << _mu_lame <<  endl << endl;

}

void Solid::set_young_module(const double young_module) {
  _young_module = young_module;
}

void Solid::set_poisson_coeff(const double poisson_coeff) {
  _poisson_coeff = poisson_coeff;
}

const unsigned Solid::get_physical_model() const{
  return _model;
}

const double Solid::get_young_module() const{
  return _young_module;
}

const double Solid::get_poisson_coeff() const{
  return _poisson_coeff;
}

const double Solid::get_lame_lambda() const{
  return _lambda_lame;
}

const double Solid::get_lame_shear_modulus() const{
  return _mu_lame;
}

const bool Solid::get_if_penalty() const{
  return _penalty;
}

const bool Solid::get_if_mass_penalty() const{
  return _mass_penalty;
}

std::ostream & operator << (std::ostream & os, const Solid & solid)
{
  os << "Density: " << solid._density << std::endl;
  os << "Young Module: " << solid._young_module << std::endl;
  os << "Poisson coeffcient: " << solid._poisson_coeff << std::endl;
  os << "Lambda Lamé: " << solid._lambda_lame << std::endl;
  os << "Mu lamé: " << solid._mu_lame << std::endl;
  os << "Physical Model: " << solid._model << std::endl;
  os << std::endl;
  return os;
}

// Take a const-reference to the right-hand side of the assignment.
// Return a non-const reference to the left-hand side.
Solid& Solid::operator=(const Solid &solid) {
  this->_parameter 			= solid._parameter;
  this->_density 			= solid._density;
  this->_thermal_conductivity 		= solid._thermal_conductivity;
  this->_heat_capacity 			= solid._heat_capacity;
  this->_thermal_expansion_coefficient 	= solid._thermal_expansion_coefficient;
  this->_young_module 			= solid._young_module;
  this->_poisson_coeff 			= solid._poisson_coeff;
  this->_lambda_lame 			= solid._lambda_lame;
  this->_mu_lame 			= solid._mu_lame;
  this->_model 				= solid._model;
  this->_penalty 			= solid._penalty;
  this->_mass_penalty 			= solid._mass_penalty;
  return *this;  // Return a reference to myself.
}

} //end namespace femus

<|endoftext|>