<commit_before>#include <cstdio>

#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "ProfilingInstrumentationPass.h"

using namespace llvm;
using cgprofiler::ProfilingInstrumentationPass;

#define DEBUG_TYPE = "ProfilingInstrumentationPass";

namespace cgprofiler {

char ProfilingInstrumentationPass::ID = 0;

}

// Returns a map (Function* -> uint64_t).
static DenseMap<Function*, uint64_t>
computeFunctionIDs(llvm::ArrayRef<Function*> functions) {
  DenseMap<Function*, uint64_t> idMap;

  size_t nextID = 0;
  for (auto f : functions) {
    idMap[f] = nextID;
    ++nextID;
  }

  return idMap;
}

// Returns a set of all internal (defined) functions.
static DenseSet<Function*>
computeInternal(llvm::ArrayRef<Function*> functions) {
  DenseSet<Function*> internal;

  for (auto f : functions) {
    if (!f->isDeclaration()) {
      internal.insert(f);
    }
  }

  return internal;
}

static llvm::Constant*
createConstantString(llvm::Module& m, llvm::StringRef str) {
  auto& context = m.getContext();

  auto* name    = llvm::ConstantDataArray::getString(context, str, true);
  auto* int8Ty  = llvm::Type::getInt8Ty(context);
  auto* arrayTy = llvm::ArrayType::get(int8Ty, str.size() + 1);
  auto* asStr   = new llvm::GlobalVariable(
      m, arrayTy, true, llvm::GlobalValue::PrivateLinkage, name);

  auto* zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0);
  llvm::Value* indices[] = {zero, zero};
  return llvm::ConstantExpr::getInBoundsGetElementPtr(arrayTy, asStr, indices);
}

// Create the CCOUNT(functionInfo) table used by the runtime library.
static void
createFunctionTable(Module& m, uint64_t numFunctions) {
  auto& context = m.getContext();

  // Create the component types of the table
  auto* int64Ty    = Type::getInt64Ty(context);
  auto* stringTy   = Type::getInt8PtrTy(context);
  Type* fieldTys[] = {stringTy, int64Ty, int64Ty};
  auto* structTy   = StructType::get(context, fieldTys, false);
  auto* tableTy    = ArrayType::get(structTy, numFunctions);
  auto* zero       = ConstantInt::get(int64Ty, 0, false);

  // Compute and store an externally visible array of function information.
  std::vector<Constant*> values;
  std::transform(
      m.begin(),
      m.end(),
      std::back_inserter(values),
      [&m, zero, structTy](auto& f) {
        Constant* structFields[] = {createConstantString(m, f.getName()), zero};
        return ConstantStruct::get(structTy, structFields);
      });
  auto* functionTable = ConstantArray::get(tableTy, values);
  new GlobalVariable(m,
                     tableTy,
                     false,
                     GlobalValue::ExternalLinkage,
                     functionTable,
                     "LLVMAnalysis_functionInfo");
}

bool
ProfilingInstrumentationPass::runOnModule(llvm::Module& m) {
  auto& context = m.getContext();

  // First identify the functions we wish to track
  std::vector<Function*> toCount;
  for (auto& f : m) {
    toCount.push_back(&f);
  }

  ids = computeFunctionIDs(toCount);
  internal = computeInternal(toCount);
  auto const numFunctions = toCount.size();

  // Store the number of functions into an externally visible variable.
  auto* int64Ty = Type::getInt64Ty(context);
  auto* numFunctionsGlobal = ConstantInt::get(int64Ty, numFunctions, false);
  new GlobalVariable(m,
                     int64Ty,
                     true,
                     GlobalValue::ExternalLinkage,
                     numFunctionsGlobal,
                     "LLVMAnalysis_numberOfFunctions");

  createFunctionTable(m, numFunctions);

  // Install the result printing function so that it prints out the counts after
  // the entire program is finished executing.
  auto* voidTy  = Type::getVoidTy(context);
  auto* printer = m.getOrInsertFunction("LLVMAnalysis_printNumOfRuns", voidTy, nullptr);
  appendToGlobalDtors(m, llvm::cast<Function>(printer), 0);

    // Declare the counter function
  auto* helperTy = FunctionType::get(voidTy, int64Ty, false);
  auto* counter  = m.getOrInsertFunction("LLVMAnalysis_functionCalled", helperTy);

  //Declare the set Line Number function
  llvm::Type* paramRef[] = {Type::getInt64Ty(context), Type::getInt64Ty(context)};
  auto* lineNumHelperTy = FunctionType::get(voidTy, paramRef, false);
  auto* lineNumFunc = m.getOrInsertFunction("LLVMAnalysis_setLineNum", lineNumHelperTy);

  for (auto f : toCount) {
    // We only want to instrument internally defined functions.
    if (f->isDeclaration()) {
      continue;
    }

    // Count each internal function as it executes.
    handleCalledFunction(*f, counter);

    // Count each external function as it is called.
    for (auto& bb : *f) {
      for (auto& i : bb) {
        handleInstruction(CallSite(&i), counter, lineNumFunc);
      }
    }
  }

  return true;
}

void
ProfilingInstrumentationPass::handleCalledFunction(Function& f, Value* counter) {
  //Count is added to first insertion point
  IRBuilder<> builder(&*f.getEntryBlock().getFirstInsertionPt());
  builder.CreateCall(counter, builder.getInt64(ids[&f]));
}

void
ProfilingInstrumentationPass::handleInstruction(CallSite cs, Value* counter, Value* lineNumFunc) {
  // auto& context = cs->getContext();
  // Check whether the instruction is actually a call
  if (!cs.getInstruction()) {
    return;
  }
  uint64_t lineNum = 0;

  if (const Instruction *inst = dyn_cast<Instruction>(cs.getInstruction())){
    MDNode *N = inst->getMetadata("dbg");
    DebugLoc Loc = DebugLoc(N);
    if (Loc){
      lineNum = 99;
    }
    // StringRef fileName = Loc.getFilename();
  }

  // Check whether the called function is directly invoked
  auto called = dyn_cast<Function>(cs.getCalledValue()->stripPointerCasts());
  if (!called) {
    return;
  }

  IRBuilder<> builder2(cs.getInstruction());
  llvm::Value* paramRef[] = {builder2.getInt64(ids[called]), builder2.getInt64(lineNum)};
  builder2.CreateCall(lineNumFunc, paramRef);

  // Check if the function is internal or blacklisted.
  if (internal.count(called) || !ids.count(called)) {
    // Internal functions are counted upon the entry of each function body.
    // Blacklisted functions are not counted. Neither should proceed.
    return;
  }

  // External functions are counted at their invocation sites.
  IRBuilder<> builder(cs.getInstruction());
  builder.CreateCall(counter, builder.getInt64(ids[called]));
}
<commit_msg>original way<commit_after>#include <cstdio>

#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "ProfilingInstrumentationPass.h"

using namespace llvm;
using cgprofiler::ProfilingInstrumentationPass;

#define DEBUG_TYPE = "ProfilingInstrumentationPass";

namespace cgprofiler {

char ProfilingInstrumentationPass::ID = 0;

}

// Returns a map (Function* -> uint64_t).
static DenseMap<Function*, uint64_t>
computeFunctionIDs(llvm::ArrayRef<Function*> functions) {
  DenseMap<Function*, uint64_t> idMap;

  size_t nextID = 0;
  for (auto f : functions) {
    idMap[f] = nextID;
    ++nextID;
  }

  return idMap;
}

// Returns a set of all internal (defined) functions.
static DenseSet<Function*>
computeInternal(llvm::ArrayRef<Function*> functions) {
  DenseSet<Function*> internal;

  for (auto f : functions) {
    if (!f->isDeclaration()) {
      internal.insert(f);
    }
  }

  return internal;
}

static llvm::Constant*
createConstantString(llvm::Module& m, llvm::StringRef str) {
  auto& context = m.getContext();

  auto* name    = llvm::ConstantDataArray::getString(context, str, true);
  auto* int8Ty  = llvm::Type::getInt8Ty(context);
  auto* arrayTy = llvm::ArrayType::get(int8Ty, str.size() + 1);
  auto* asStr   = new llvm::GlobalVariable(
      m, arrayTy, true, llvm::GlobalValue::PrivateLinkage, name);

  auto* zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0);
  llvm::Value* indices[] = {zero, zero};
  return llvm::ConstantExpr::getInBoundsGetElementPtr(arrayTy, asStr, indices);
}

// Create the CCOUNT(functionInfo) table used by the runtime library.
static void
createFunctionTable(Module& m, uint64_t numFunctions) {
  auto& context = m.getContext();

  // Create the component types of the table
  auto* int64Ty    = Type::getInt64Ty(context);
  auto* stringTy   = Type::getInt8PtrTy(context);
  Type* fieldTys[] = {stringTy, int64Ty, int64Ty};
  auto* structTy   = StructType::get(context, fieldTys, false);
  auto* tableTy    = ArrayType::get(structTy, numFunctions);
  auto* zero       = ConstantInt::get(int64Ty, 0, false);

  // Compute and store an externally visible array of function information.
  std::vector<Constant*> values;
  std::transform(
      m.begin(),
      m.end(),
      std::back_inserter(values),
      [&m, zero, structTy](auto& f) {
        Constant* structFields[] = {createConstantString(m, f.getName()), zero};
        return ConstantStruct::get(structTy, structFields);
      });
  auto* functionTable = ConstantArray::get(tableTy, values);
  new GlobalVariable(m,
                     tableTy,
                     false,
                     GlobalValue::ExternalLinkage,
                     functionTable,
                     "LLVMAnalysis_functionInfo");
}

bool
ProfilingInstrumentationPass::runOnModule(llvm::Module& m) {
  auto& context = m.getContext();

  // First identify the functions we wish to track
  std::vector<Function*> toCount;
  for (auto& f : m) {
    toCount.push_back(&f);
  }

  ids = computeFunctionIDs(toCount);
  internal = computeInternal(toCount);
  auto const numFunctions = toCount.size();

  // Store the number of functions into an externally visible variable.
  auto* int64Ty = Type::getInt64Ty(context);
  auto* numFunctionsGlobal = ConstantInt::get(int64Ty, numFunctions, false);
  new GlobalVariable(m,
                     int64Ty,
                     true,
                     GlobalValue::ExternalLinkage,
                     numFunctionsGlobal,
                     "LLVMAnalysis_numberOfFunctions");

  createFunctionTable(m, numFunctions);

  // Install the result printing function so that it prints out the counts after
  // the entire program is finished executing.
  auto* voidTy  = Type::getVoidTy(context);
  auto* printer = m.getOrInsertFunction("LLVMAnalysis_printNumOfRuns", voidTy, nullptr);
  appendToGlobalDtors(m, llvm::cast<Function>(printer), 0);

    // Declare the counter function
  auto* helperTy = FunctionType::get(voidTy, int64Ty, false);
  auto* counter  = m.getOrInsertFunction("LLVMAnalysis_functionCalled", helperTy);

  //Declare the set Line Number function
  llvm::Type* paramRef[] = {Type::getInt64Ty(context), Type::getInt64Ty(context)};
  auto* lineNumHelperTy = FunctionType::get(voidTy, paramRef, false);
  auto* lineNumFunc = m.getOrInsertFunction("LLVMAnalysis_setLineNum", lineNumHelperTy);

  for (auto f : toCount) {
    // We only want to instrument internally defined functions.
    if (f->isDeclaration()) {
      continue;
    }

    // Count each internal function as it executes.
    handleCalledFunction(*f, counter);

    // Count each external function as it is called.
    for (auto& bb : *f) {
      for (auto& i : bb) {
        handleInstruction(CallSite(&i), counter, lineNumFunc);
      }
    }
  }

  return true;
}

void
ProfilingInstrumentationPass::handleCalledFunction(Function& f, Value* counter) {
  //Count is added to first insertion point
  IRBuilder<> builder(&*f.getEntryBlock().getFirstInsertionPt());
  builder.CreateCall(counter, builder.getInt64(ids[&f]));
}

void
ProfilingInstrumentationPass::handleInstruction(CallSite cs, Value* counter, Value* lineNumFunc) {
  // auto& context = cs->getContext();
  // Check whether the instruction is actually a call
  if (!cs.getInstruction()) {
    return;
  }
  uint64_t lineNum = 0;

  if (DILocation *Loc = cs.getInstruction()->getDebugLoc()){
    lineNum = Loc->getLine();
    // StringRef fileName = Loc.getFilename();
  }

  // Check whether the called function is directly invoked
  auto called = dyn_cast<Function>(cs.getCalledValue()->stripPointerCasts());
  if (!called) {
    return;
  }

  IRBuilder<> builder2(cs.getInstruction());
  llvm::Value* paramRef[] = {builder2.getInt64(ids[called]), builder2.getInt64(lineNum)};
  builder2.CreateCall(lineNumFunc, paramRef);

  // Check if the function is internal or blacklisted.
  if (internal.count(called) || !ids.count(called)) {
    // Internal functions are counted upon the entry of each function body.
    // Blacklisted functions are not counted. Neither should proceed.
    return;
  }

  // External functions are counted at their invocation sites.
  IRBuilder<> builder(cs.getInstruction());
  builder.CreateCall(counter, builder.getInt64(ids[called]));
}
<|endoftext|>


<commit_before>#include "client.hh"

#include "face_registry.hh"
#include "context.hh"
#include "buffer_manager.hh"
#include "user_interface.hh"
#include "file.hh"
#include "remote.hh"
#include "client_manager.hh"
#include "event_manager.hh"
#include "window.hh"

#include <signal.h>
#include <unistd.h>

namespace Kakoune
{

Client::Client(std::unique_ptr<UserInterface>&& ui,
               std::unique_ptr<Window>&& window,
               SelectionList selections,
               EnvVarMap env_vars,
               String name)
    : m_ui{std::move(ui)}, m_window{std::move(window)},
      m_input_handler{std::move(selections), Context::Flags::None,
                      std::move(name)},
      m_env_vars(env_vars)
{
    context().set_client(*this);
    context().set_window(*m_window);

    m_window->options().register_watcher(*this);
    m_ui->set_ui_options(m_window->options()["ui_options"].get<UserInterface::Options>());
}

Client::~Client()
{
    m_window->options().unregister_watcher(*this);
}

Optional<Key> Client::get_next_key(EventMode mode)
{
    if (not m_pending_keys.empty())
    {
        Key key = m_pending_keys.front();
        m_pending_keys.erase(m_pending_keys.begin());
        return key;
    }
    if (mode != EventMode::Pending and m_ui->is_key_available())
        return m_ui->get_key();
    return {};
}

void Client::handle_available_input(EventMode mode)
{
    if (mode == EventMode::Urgent)
    {
        Key key = m_ui->get_key();
        if (key == ctrl('c'))
            killpg(getpgrp(), SIGINT);
        else
            m_pending_keys.push_back(key);
    }
    else
    {
        try
        {
            while (Optional<Key> key = get_next_key(mode))
            {
                if (*key == ctrl('c'))
                    killpg(getpgrp(), SIGINT);
                else
                {
                    m_input_handler.handle_key(*key);
                    m_input_handler.clear_mode_trash();
                    context().window().forget_timestamp();
                }
            }
        }
        catch (Kakoune::runtime_error& error)
        {
            context().print_status({ error.what(), get_face("Error") });
            context().hooks().run_hook("RuntimeError", error.what(), context());
        }
        catch (Kakoune::client_removed&)
        {
            ClientManager::instance().remove_client(*this);
        }
    }
}

void Client::print_status(DisplayLine status_line)
{
    m_pending_status_line = std::move(status_line);
}

DisplayLine Client::generate_mode_line() const
{
    auto pos = context().selections().main().cursor();
    auto col = context().buffer()[pos.line].char_count_to(pos.column);

    DisplayLine status;
    Face info_face = get_face("Information");
    Face status_face = get_face("StatusLine");

    status.push_back({ context().buffer().display_name(), status_face });
    status.push_back({ " " + to_string((int)pos.line+1) + ":" + to_string((int)col+1) + " ", status_face });
    if (context().buffer().is_modified())
        status.push_back({ "[+]", info_face });
    if (m_input_handler.is_recording())
        status.push_back({ "[recording ("_str + StringView{m_input_handler.recording_reg()} + ")]", info_face });
    if (context().buffer().flags() & Buffer::Flags::New)
        status.push_back({ "[new file]", info_face });
    if (context().user_hooks_support().is_disabled())
        status.push_back({ "[no-hooks]", info_face });
    if (context().buffer().flags() & Buffer::Flags::Fifo)
        status.push_back({ "[fifo]", info_face });
    status.push_back({ " ", status_face });
    for (auto& atom : m_input_handler.mode_line())
        status.push_back(std::move(atom));
    status.push_back({ " - " + context().name() + "@[" + Server::instance().session() + "]", status_face });

    return status;
}

void Client::change_buffer(Buffer& buffer)
{
    auto& client_manager = ClientManager::instance();
    m_window->options().unregister_watcher(*this);
    client_manager.add_free_window(std::move(m_window),
                                   std::move(context().selections()));
    WindowAndSelections ws = client_manager.get_free_window(buffer);

    m_window = std::move(ws.window);
    m_window->options().register_watcher(*this);
    m_ui->set_ui_options(m_window->options()["ui_options"].get<UserInterface::Options>());

    context().m_selections = std::move(ws.selections);
    context().set_window(*m_window);
    m_window->set_dimensions(ui().dimensions());

    m_window->hooks().run_hook("WinDisplay", buffer.name(), context());
}

void Client::redraw_ifn()
{
    DisplayLine mode_line = generate_mode_line();
    const bool buffer_changed = context().window().timestamp() != context().buffer().timestamp();
    const bool mode_line_changed = mode_line.atoms() != m_mode_line.atoms();
    const bool status_line_changed = m_status_line.atoms() != m_pending_status_line.atoms();
    if (buffer_changed or status_line_changed or mode_line_changed)
    {
        if (buffer_changed)
        {
            CharCoord dimensions = context().ui().dimensions();
            if (dimensions == CharCoord{0,0})
                return;
            context().window().set_dimensions(dimensions);
            context().window().update_display_buffer(context());
        }
        m_mode_line = std::move(mode_line);
        m_status_line = m_pending_status_line;
        context().ui().draw(context().window().display_buffer(),
                            m_status_line, m_mode_line);
    }
    context().ui().refresh();
}

static void reload_buffer(Context& context, StringView filename)
{
    CharCoord view_pos = context.window().position();
    ByteCoord cursor_pos = context.selections().main().cursor();
    Buffer* buf = create_buffer_from_file(filename);
    if (not buf)
        return;
    context.change_buffer(*buf);
    context.selections() = SelectionList{ *buf, buf->clamp(cursor_pos)};
    context.window().set_position(view_pos);
    context.print_status({ "'" + buf->display_name() + "' reloaded",
                           get_face("Information") });
}

void Client::check_buffer_fs_timestamp()
{
    Buffer& buffer = context().buffer();
    auto reload = context().options()["autoreload"].get<YesNoAsk>();
    if (not (buffer.flags() & Buffer::Flags::File) or reload == No)
        return;

    const String& filename = buffer.name();
    time_t ts = get_fs_timestamp(filename);
    if (ts == InvalidTime or ts == buffer.fs_timestamp())
        return;
    if (reload == Ask)
    {
        m_ui->info_show(
            "reload '" + buffer.display_name() + "' ?",
            "'" + buffer.display_name() + "' was modified externally\n"
            "press r or y to reload, k or n to keep",
            CharCoord{}, get_face("Information"), InfoStyle::Prompt);

        m_input_handler.on_next_key(KeymapMode::None,
                                   [this, filename](Key key, Context& context) {
            m_ui->info_hide();

            Buffer* buf = BufferManager::instance().get_buffer_ifp(filename);
            // buffer got deleted while waiting for the key, do nothing
            if (not buf)
                return;
            if (key == 'r' or key == 'y')
                reload_buffer(context, filename);
            else if (key == 'k' or key == 'n')
            {
                // reread timestamp in case the file was modified again
                buf->set_fs_timestamp(get_fs_timestamp(filename));
                print_status({ "'" + buf->display_name() + "' kept",
                               get_face("Information") });
            }
            else
            {
                print_status({ "'" + key_to_str(key) + "' is not a valid choice",
                               get_face("Error") });
                check_buffer_fs_timestamp();
            }
        });
    }
    else
        reload_buffer(context(), filename);
}

StringView Client::get_env_var(const String& name) const
{
    auto it = m_env_vars.find(name);
    if (it == m_env_vars.end())
        return {};
    return it->second;
}

void Client::on_option_changed(const Option& option)
{
    if (option.name() == "ui_options")
        m_ui->set_ui_options(option.get<UserInterface::Options>());
}

}
<commit_msg>Allow <ret> and <esc> to reload/keep an externally modified file<commit_after>#include "client.hh"

#include "face_registry.hh"
#include "context.hh"
#include "buffer_manager.hh"
#include "user_interface.hh"
#include "file.hh"
#include "remote.hh"
#include "client_manager.hh"
#include "event_manager.hh"
#include "window.hh"

#include <signal.h>
#include <unistd.h>

namespace Kakoune
{

Client::Client(std::unique_ptr<UserInterface>&& ui,
               std::unique_ptr<Window>&& window,
               SelectionList selections,
               EnvVarMap env_vars,
               String name)
    : m_ui{std::move(ui)}, m_window{std::move(window)},
      m_input_handler{std::move(selections), Context::Flags::None,
                      std::move(name)},
      m_env_vars(env_vars)
{
    context().set_client(*this);
    context().set_window(*m_window);

    m_window->options().register_watcher(*this);
    m_ui->set_ui_options(m_window->options()["ui_options"].get<UserInterface::Options>());
}

Client::~Client()
{
    m_window->options().unregister_watcher(*this);
}

Optional<Key> Client::get_next_key(EventMode mode)
{
    if (not m_pending_keys.empty())
    {
        Key key = m_pending_keys.front();
        m_pending_keys.erase(m_pending_keys.begin());
        return key;
    }
    if (mode != EventMode::Pending and m_ui->is_key_available())
        return m_ui->get_key();
    return {};
}

void Client::handle_available_input(EventMode mode)
{
    if (mode == EventMode::Urgent)
    {
        Key key = m_ui->get_key();
        if (key == ctrl('c'))
            killpg(getpgrp(), SIGINT);
        else
            m_pending_keys.push_back(key);
    }
    else
    {
        try
        {
            while (Optional<Key> key = get_next_key(mode))
            {
                if (*key == ctrl('c'))
                    killpg(getpgrp(), SIGINT);
                else
                {
                    m_input_handler.handle_key(*key);
                    m_input_handler.clear_mode_trash();
                    context().window().forget_timestamp();
                }
            }
        }
        catch (Kakoune::runtime_error& error)
        {
            context().print_status({ error.what(), get_face("Error") });
            context().hooks().run_hook("RuntimeError", error.what(), context());
        }
        catch (Kakoune::client_removed&)
        {
            ClientManager::instance().remove_client(*this);
        }
    }
}

void Client::print_status(DisplayLine status_line)
{
    m_pending_status_line = std::move(status_line);
}

DisplayLine Client::generate_mode_line() const
{
    auto pos = context().selections().main().cursor();
    auto col = context().buffer()[pos.line].char_count_to(pos.column);

    DisplayLine status;
    Face info_face = get_face("Information");
    Face status_face = get_face("StatusLine");

    status.push_back({ context().buffer().display_name(), status_face });
    status.push_back({ " " + to_string((int)pos.line+1) + ":" + to_string((int)col+1) + " ", status_face });
    if (context().buffer().is_modified())
        status.push_back({ "[+]", info_face });
    if (m_input_handler.is_recording())
        status.push_back({ "[recording ("_str + StringView{m_input_handler.recording_reg()} + ")]", info_face });
    if (context().buffer().flags() & Buffer::Flags::New)
        status.push_back({ "[new file]", info_face });
    if (context().user_hooks_support().is_disabled())
        status.push_back({ "[no-hooks]", info_face });
    if (context().buffer().flags() & Buffer::Flags::Fifo)
        status.push_back({ "[fifo]", info_face });
    status.push_back({ " ", status_face });
    for (auto& atom : m_input_handler.mode_line())
        status.push_back(std::move(atom));
    status.push_back({ " - " + context().name() + "@[" + Server::instance().session() + "]", status_face });

    return status;
}

void Client::change_buffer(Buffer& buffer)
{
    auto& client_manager = ClientManager::instance();
    m_window->options().unregister_watcher(*this);
    client_manager.add_free_window(std::move(m_window),
                                   std::move(context().selections()));
    WindowAndSelections ws = client_manager.get_free_window(buffer);

    m_window = std::move(ws.window);
    m_window->options().register_watcher(*this);
    m_ui->set_ui_options(m_window->options()["ui_options"].get<UserInterface::Options>());

    context().m_selections = std::move(ws.selections);
    context().set_window(*m_window);
    m_window->set_dimensions(ui().dimensions());

    m_window->hooks().run_hook("WinDisplay", buffer.name(), context());
}

void Client::redraw_ifn()
{
    DisplayLine mode_line = generate_mode_line();
    const bool buffer_changed = context().window().timestamp() != context().buffer().timestamp();
    const bool mode_line_changed = mode_line.atoms() != m_mode_line.atoms();
    const bool status_line_changed = m_status_line.atoms() != m_pending_status_line.atoms();
    if (buffer_changed or status_line_changed or mode_line_changed)
    {
        if (buffer_changed)
        {
            CharCoord dimensions = context().ui().dimensions();
            if (dimensions == CharCoord{0,0})
                return;
            context().window().set_dimensions(dimensions);
            context().window().update_display_buffer(context());
        }
        m_mode_line = std::move(mode_line);
        m_status_line = m_pending_status_line;
        context().ui().draw(context().window().display_buffer(),
                            m_status_line, m_mode_line);
    }
    context().ui().refresh();
}

static void reload_buffer(Context& context, StringView filename)
{
    CharCoord view_pos = context.window().position();
    ByteCoord cursor_pos = context.selections().main().cursor();
    Buffer* buf = create_buffer_from_file(filename);
    if (not buf)
        return;
    context.change_buffer(*buf);
    context.selections() = SelectionList{ *buf, buf->clamp(cursor_pos)};
    context.window().set_position(view_pos);
    context.print_status({ "'" + buf->display_name() + "' reloaded",
                           get_face("Information") });
}

void Client::check_buffer_fs_timestamp()
{
    Buffer& buffer = context().buffer();
    auto reload = context().options()["autoreload"].get<YesNoAsk>();
    if (not (buffer.flags() & Buffer::Flags::File) or reload == No)
        return;

    const String& filename = buffer.name();
    time_t ts = get_fs_timestamp(filename);
    if (ts == InvalidTime or ts == buffer.fs_timestamp())
        return;
    if (reload == Ask)
    {
        m_ui->info_show(
            "reload '" + buffer.display_name() + "' ?",
            "'" + buffer.display_name() + "' was modified externally\n"
            "press <ret>, r or y to reload, <esc>, k or n to keep",
            CharCoord{}, get_face("Information"), InfoStyle::Prompt);

        m_input_handler.on_next_key(KeymapMode::None,
                                   [this, filename](Key key, Context& context) {
            m_ui->info_hide();

            Buffer* buf = BufferManager::instance().get_buffer_ifp(filename);
            // buffer got deleted while waiting for the key, do nothing
            if (not buf)
                return;
            if (key == 'r' or key == 'y' or key == ctrl('m'))
                reload_buffer(context, filename);
            else if (key == 'k' or key == 'n' or key == Key::Escape)
            {
                // reread timestamp in case the file was modified again
                buf->set_fs_timestamp(get_fs_timestamp(filename));
                print_status({ "'" + buf->display_name() + "' kept",
                               get_face("Information") });
            }
            else
            {
                print_status({ "'" + key_to_str(key) + "' is not a valid choice",
                               get_face("Error") });
                check_buffer_fs_timestamp();
            }
        });
    }
    else
        reload_buffer(context(), filename);
}

StringView Client::get_env_var(const String& name) const
{
    auto it = m_env_vars.find(name);
    if (it == m_env_vars.end())
        return {};
    return it->second;
}

void Client::on_option_changed(const Option& option)
{
    if (option.name() == "ui_options")
        m_ui->set_ui_options(option.get<UserInterface::Options>());
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2007 Rony Shapiro <ronys@users.sourceforge.net>.
 * All rights reserved. Use of the code is allowed under the
 * Artistic License terms, as specified in the LICENSE file
 * distributed with this code, or available from
 * http://www.opensource.org/licenses/artistic-license.php
 */
/// \file PasskeySetup.cpp
//-----------------------------------------------------------------------------

#include "stdafx.h"
#include "PasswordSafe.h"
#include "corelib/PWCharPool.h" // for CheckPassword()
#include "ThisMfcApp.h"
#include "corelib/PwsPlatform.h"

#if defined(POCKET_PC)
  #include "pocketpc/resource.h"
  #include "pocketpc/PocketPC.h"
#else
  #include "resource.h"
  #include "resource3.h"  // String resources
#endif

#include "corelib/util.h"

#include "PasskeySetup.h"
#include "PwFont.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

static TCHAR PSSWDCHAR = TCHAR('*');

//-----------------------------------------------------------------------------
CPasskeySetup::CPasskeySetup(CWnd* pParent)
   : CPWDialog(CPasskeySetup::IDD, pParent)
{
   m_passkey = _T("");
   m_verify = _T("");
}

BOOL CPasskeySetup::OnInitDialog()
{
   CPWDialog::OnInitDialog();
   SetPasswordFont(GetDlgItem(IDC_PASSKEY));
   SetPasswordFont(GetDlgItem(IDC_VERIFY));
   ((CEdit*)GetDlgItem(IDC_PASSKEY))->SetPasswordChar(PSSWDCHAR);
   ((CEdit*)GetDlgItem(IDC_VERIFY))->SetPasswordChar(PSSWDCHAR);

   return TRUE;
}

void CPasskeySetup::DoDataExchange(CDataExchange* pDX)
{
   CPWDialog::DoDataExchange(pDX);
   DDX_Text(pDX, IDC_PASSKEY, (CString &)m_passkey);
   DDX_Text(pDX, IDC_VERIFY, (CString &)m_verify);
}

BEGIN_MESSAGE_MAP(CPasskeySetup, CPWDialog)
   ON_BN_CLICKED(ID_HELP, OnHelp)
#if defined(POCKET_PC)
   ON_EN_SETFOCUS(IDC_PASSKEY, OnPasskeySetfocus)
   ON_EN_SETFOCUS(IDC_VERIFY, OnPasskeySetfocus)
   ON_EN_KILLFOCUS(IDC_PASSKEY, OnPasskeyKillfocus)
   ON_EN_KILLFOCUS(IDC_VERIFY, OnPasskeyKillfocus)
#endif
END_MESSAGE_MAP()

void CPasskeySetup::OnCancel()
{
   CPWDialog::OnCancel();
}

void CPasskeySetup::OnOK()
{
  UpdateData(TRUE);
  if (m_passkey != m_verify)
    {
      AfxMessageBox(IDS_ENTRIESDONOTMATCH);
      ((CEdit*)GetDlgItem(IDC_VERIFY))->SetFocus();
      return;
    }

  if (m_passkey.IsEmpty())
    {
      AfxMessageBox(IDS_ENTERKEYANDVERIFY);
      ((CEdit*)GetDlgItem(IDC_PASSKEY))->SetFocus();
      return;
    }
  // Vox populi vox dei - folks want the ability to use a weak
  // passphrase, best we can do is warn them...
  // If someone want to build a version that insists on proper
  // passphrases, then just define the preprocessor macro
  // PWS_FORCE_STRONG_PASSPHRASE in the build properties/Makefile
  // (also used in CPasskeyChangeDlg)
#ifndef _DEBUG // for debug, we want no checks at all, to save time
  CMyString errmess;
  if (!CPasswordCharPool::CheckPassword(m_passkey, errmess)) {
  	CString cs_msg, cs_text;
    cs_msg.Format(IDS_WEAKPASSPHRASE, errmess);
#ifndef PWS_FORCE_STRONG_PASSPHRASE
    cs_text.LoadString(IDS_USEITANYWAY);
    cs_msg += cs_text;
    int rc = AfxMessageBox(cs_msg, MB_YESNO | MB_ICONSTOP);
    if (rc == IDNO)
      return;
#else
    cs_text.LoadString(IDS_TRYANOTHER);
    cs_msg += cs_text;
    AfxMessageBox(cs_msg, MB_OK | MB_ICONSTOP);
    return
#endif // PWS_FORCE_STRONG_PASSPHRASE
  }
#endif // _DEBUG

  CPWDialog::OnOK();
}

void CPasskeySetup::OnHelp()
{
#if defined(POCKET_PC)
  CreateProcess( _T("PegHelp.exe"), _T("pws_ce_help.html#newdatabase"), NULL, NULL, FALSE, 0, NULL, NULL, NULL, NULL );
#else
  CString cs_HelpTopic;
  cs_HelpTopic = app.GetHelpFileName() + _T("::/html/create_new_db.html");
  HtmlHelp(DWORD_PTR((LPCTSTR)cs_HelpTopic), HH_DISPLAY_TOPIC);
#endif
}

#if defined(POCKET_PC)
/************************************************************************/
/* Restore the state of word completion when the password field loses   */
/* focus.                                                               */
/************************************************************************/
void CPasskeySetup::OnPasskeyKillfocus()
{
	EnableWordCompletion( m_hWnd );
}

/************************************************************************/
/* When the password field is activated, pull up the SIP and disable    */
/* word completion.                                                     */
/************************************************************************/
void CPasskeySetup::OnPasskeySetfocus()
{
	DisableWordCompletion( m_hWnd );
}
#endif

//-----------------------------------------------------------------------------
<commit_msg>[1788426] - Fixed compilation error under PWS_FORCE_STRONG_PASSPHRASE<commit_after>/*
 * Copyright (c) 2003-2007 Rony Shapiro <ronys@users.sourceforge.net>.
 * All rights reserved. Use of the code is allowed under the
 * Artistic License terms, as specified in the LICENSE file
 * distributed with this code, or available from
 * http://www.opensource.org/licenses/artistic-license.php
 */
/// \file PasskeySetup.cpp
//-----------------------------------------------------------------------------

#include "stdafx.h"
#include "PasswordSafe.h"
#include "corelib/PWCharPool.h" // for CheckPassword()
#include "ThisMfcApp.h"
#include "corelib/PwsPlatform.h"

#if defined(POCKET_PC)
  #include "pocketpc/resource.h"
  #include "pocketpc/PocketPC.h"
#else
  #include "resource.h"
  #include "resource3.h"  // String resources
#endif

#include "corelib/util.h"

#include "PasskeySetup.h"
#include "PwFont.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

static TCHAR PSSWDCHAR = TCHAR('*');

//-----------------------------------------------------------------------------
CPasskeySetup::CPasskeySetup(CWnd* pParent)
   : CPWDialog(CPasskeySetup::IDD, pParent)
{
   m_passkey = _T("");
   m_verify = _T("");
}

BOOL CPasskeySetup::OnInitDialog()
{
   CPWDialog::OnInitDialog();
   SetPasswordFont(GetDlgItem(IDC_PASSKEY));
   SetPasswordFont(GetDlgItem(IDC_VERIFY));
   ((CEdit*)GetDlgItem(IDC_PASSKEY))->SetPasswordChar(PSSWDCHAR);
   ((CEdit*)GetDlgItem(IDC_VERIFY))->SetPasswordChar(PSSWDCHAR);

   return TRUE;
}

void CPasskeySetup::DoDataExchange(CDataExchange* pDX)
{
   CPWDialog::DoDataExchange(pDX);
   DDX_Text(pDX, IDC_PASSKEY, (CString &)m_passkey);
   DDX_Text(pDX, IDC_VERIFY, (CString &)m_verify);
}

BEGIN_MESSAGE_MAP(CPasskeySetup, CPWDialog)
   ON_BN_CLICKED(ID_HELP, OnHelp)
#if defined(POCKET_PC)
   ON_EN_SETFOCUS(IDC_PASSKEY, OnPasskeySetfocus)
   ON_EN_SETFOCUS(IDC_VERIFY, OnPasskeySetfocus)
   ON_EN_KILLFOCUS(IDC_PASSKEY, OnPasskeyKillfocus)
   ON_EN_KILLFOCUS(IDC_VERIFY, OnPasskeyKillfocus)
#endif
END_MESSAGE_MAP()

void CPasskeySetup::OnCancel()
{
   CPWDialog::OnCancel();
}

void CPasskeySetup::OnOK()
{
  UpdateData(TRUE);
  if (m_passkey != m_verify)
    {
      AfxMessageBox(IDS_ENTRIESDONOTMATCH);
      ((CEdit*)GetDlgItem(IDC_VERIFY))->SetFocus();
      return;
    }

  if (m_passkey.IsEmpty())
    {
      AfxMessageBox(IDS_ENTERKEYANDVERIFY);
      ((CEdit*)GetDlgItem(IDC_PASSKEY))->SetFocus();
      return;
    }
  // Vox populi vox dei - folks want the ability to use a weak
  // passphrase, best we can do is warn them...
  // If someone want to build a version that insists on proper
  // passphrases, then just define the preprocessor macro
  // PWS_FORCE_STRONG_PASSPHRASE in the build properties/Makefile
  // (also used in CPasskeyChangeDlg)
#ifndef _DEBUG // for debug, we want no checks at all, to save time
  CMyString errmess;
  if (!CPasswordCharPool::CheckPassword(m_passkey, errmess)) {
  	CString cs_msg, cs_text;
    cs_msg.Format(IDS_WEAKPASSPHRASE, errmess);
#ifndef PWS_FORCE_STRONG_PASSPHRASE
    cs_text.LoadString(IDS_USEITANYWAY);
    cs_msg += cs_text;
    int rc = AfxMessageBox(cs_msg, MB_YESNO | MB_ICONSTOP);
    if (rc == IDNO)
      return;
#else
    cs_text.LoadString(IDS_TRYANOTHER);
    cs_msg += cs_text;
    AfxMessageBox(cs_msg, MB_OK | MB_ICONSTOP);
    return;
#endif // PWS_FORCE_STRONG_PASSPHRASE
  }
#endif // _DEBUG

  CPWDialog::OnOK();
}

void CPasskeySetup::OnHelp()
{
#if defined(POCKET_PC)
  CreateProcess( _T("PegHelp.exe"), _T("pws_ce_help.html#newdatabase"), NULL, NULL, FALSE, 0, NULL, NULL, NULL, NULL );
#else
  CString cs_HelpTopic;
  cs_HelpTopic = app.GetHelpFileName() + _T("::/html/create_new_db.html");
  HtmlHelp(DWORD_PTR((LPCTSTR)cs_HelpTopic), HH_DISPLAY_TOPIC);
#endif
}

#if defined(POCKET_PC)
/************************************************************************/
/* Restore the state of word completion when the password field loses   */
/* focus.                                                               */
/************************************************************************/
void CPasskeySetup::OnPasskeyKillfocus()
{
	EnableWordCompletion( m_hWnd );
}

/************************************************************************/
/* When the password field is activated, pull up the SIP and disable    */
/* word completion.                                                     */
/************************************************************************/
void CPasskeySetup::OnPasskeySetfocus()
{
	DisableWordCompletion( m_hWnd );
}
#endif

//-----------------------------------------------------------------------------
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gl/vsync_provider.h"

#include "base/time.h"

namespace gfx {

VSyncProvider::VSyncProvider() {
}

VSyncProvider::~VSyncProvider() {
}

SyncControlVSyncProvider::SyncControlVSyncProvider()
    : VSyncProvider(),
      last_media_stream_counter_(0) {
  // On platforms where we can't get an accurate reading on the refresh
  // rate we fall back to the assumption that we're displaying 60 frames
  // per second.
  last_good_interval_ = base::TimeDelta::FromSeconds(1) / 60;
}

SyncControlVSyncProvider::~SyncControlVSyncProvider() {
}

void SyncControlVSyncProvider::GetVSyncParameters(
    const UpdateVSyncCallback& callback) {
#if defined(OS_LINUX)
  base::TimeTicks timebase;

  // The actual clock used for the system time returned by glXGetSyncValuesOML
  // is unspecified. In practice, the clock used is likely to be either
  // CLOCK_REALTIME or CLOCK_MONOTONIC, so we compare the returned time to the
  // current time according to both clocks, and assume that the returned time
  // was produced by the clock whose current time is closest to it, subject
  // to the restriction that the returned time must not be in the future
  // (since it is the time of a vblank that has already occurred).
  int64 system_time;
  int64 media_stream_counter;
  int64 swap_buffer_counter;
  if (!GetSyncValues(&system_time,
                     &media_stream_counter,
                     &swap_buffer_counter))
    return;

  struct timespec real_time;
  struct timespec monotonic_time;
  clock_gettime(CLOCK_REALTIME, &real_time);
  clock_gettime(CLOCK_MONOTONIC, &monotonic_time);

  int64 real_time_in_microseconds =
    real_time.tv_sec * base::Time::kMicrosecondsPerSecond +
    real_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
  int64 monotonic_time_in_microseconds =
    monotonic_time.tv_sec * base::Time::kMicrosecondsPerSecond +
    monotonic_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond;

  // We need the time according to CLOCK_MONOTONIC, so if we've been given
  // a time from CLOCK_REALTIME, we need to convert.
  bool time_conversion_needed =
      llabs(system_time - real_time_in_microseconds) <
      llabs(system_time - monotonic_time_in_microseconds);

  if (time_conversion_needed)
    system_time += monotonic_time_in_microseconds - real_time_in_microseconds;

  // Return if |system_time| is more than 1 frames in the future.
  int64 interval_in_microseconds = last_good_interval_.InMicroseconds();
  if (system_time > monotonic_time_in_microseconds + interval_in_microseconds)
    return;

  // If |system_time| is slightly in the future, adjust it to the previous
  // frame and use the last frame counter to prevent issues in the callback.
  if (system_time > monotonic_time_in_microseconds) {
    system_time -= interval_in_microseconds;
    media_stream_counter--;
  }

  timebase = base::TimeTicks::FromInternalValue(system_time);

  int32 numerator, denominator;
  if (GetMscRate(&numerator, &denominator)) {
    last_good_interval_ =
        base::TimeDelta::FromSeconds(denominator) / numerator;
  } else if (!last_timebase_.is_null()) {
    base::TimeDelta timebase_diff = timebase - last_timebase_;
    uint64 counter_diff = media_stream_counter -
        last_media_stream_counter_;
    if (counter_diff > 0 && timebase > last_timebase_)
      last_good_interval_ = timebase_diff / counter_diff;
  }
  last_timebase_ = timebase;
  last_media_stream_counter_ = media_stream_counter;
  callback.Run(timebase, last_good_interval_);
#endif  // defined(OS_LINUX)
}

}  // namespace gfx
<commit_msg>CrOS: Crash (not hang) on bad vsync refresh interval.<commit_after>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gl/vsync_provider.h"

#include "base/logging.h"
#include "base/time.h"

namespace {

// These constants define a reasonable range for a calculated refresh interval.
// Calculating refreshes out of this range will be considered a fatal error.
const int64 kMinVsyncIntervalUs = base::Time::kMicrosecondsPerSecond / 400;
const int64 kMaxVsyncIntervalUs = base::Time::kMicrosecondsPerSecond / 10;

}  // namespace

namespace gfx {

VSyncProvider::VSyncProvider() {
}

VSyncProvider::~VSyncProvider() {
}

SyncControlVSyncProvider::SyncControlVSyncProvider()
    : VSyncProvider(),
      last_media_stream_counter_(0) {
  // On platforms where we can't get an accurate reading on the refresh
  // rate we fall back to the assumption that we're displaying 60 frames
  // per second.
  last_good_interval_ = base::TimeDelta::FromSeconds(1) / 60;
}

SyncControlVSyncProvider::~SyncControlVSyncProvider() {
}

void SyncControlVSyncProvider::GetVSyncParameters(
    const UpdateVSyncCallback& callback) {
#if defined(OS_LINUX)
  base::TimeTicks timebase;

  // The actual clock used for the system time returned by glXGetSyncValuesOML
  // is unspecified. In practice, the clock used is likely to be either
  // CLOCK_REALTIME or CLOCK_MONOTONIC, so we compare the returned time to the
  // current time according to both clocks, and assume that the returned time
  // was produced by the clock whose current time is closest to it, subject
  // to the restriction that the returned time must not be in the future
  // (since it is the time of a vblank that has already occurred).
  int64 system_time;
  int64 media_stream_counter;
  int64 swap_buffer_counter;
  if (!GetSyncValues(&system_time,
                     &media_stream_counter,
                     &swap_buffer_counter))
    return;

  struct timespec real_time;
  struct timespec monotonic_time;
  clock_gettime(CLOCK_REALTIME, &real_time);
  clock_gettime(CLOCK_MONOTONIC, &monotonic_time);

  int64 real_time_in_microseconds =
    real_time.tv_sec * base::Time::kMicrosecondsPerSecond +
    real_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
  int64 monotonic_time_in_microseconds =
    monotonic_time.tv_sec * base::Time::kMicrosecondsPerSecond +
    monotonic_time.tv_nsec / base::Time::kNanosecondsPerMicrosecond;

  // We need the time according to CLOCK_MONOTONIC, so if we've been given
  // a time from CLOCK_REALTIME, we need to convert.
  bool time_conversion_needed =
      llabs(system_time - real_time_in_microseconds) <
      llabs(system_time - monotonic_time_in_microseconds);

  if (time_conversion_needed)
    system_time += monotonic_time_in_microseconds - real_time_in_microseconds;

  // Return if |system_time| is more than 1 frames in the future.
  int64 interval_in_microseconds = last_good_interval_.InMicroseconds();
  if (system_time > monotonic_time_in_microseconds + interval_in_microseconds)
    return;

  // If |system_time| is slightly in the future, adjust it to the previous
  // frame and use the last frame counter to prevent issues in the callback.
  if (system_time > monotonic_time_in_microseconds) {
    system_time -= interval_in_microseconds;
    media_stream_counter--;
  }

  timebase = base::TimeTicks::FromInternalValue(system_time);

  int32 numerator, denominator;
  if (GetMscRate(&numerator, &denominator)) {
    last_good_interval_ =
        base::TimeDelta::FromSeconds(denominator) / numerator;
  } else if (!last_timebase_.is_null()) {
    base::TimeDelta timebase_diff = timebase - last_timebase_;
    uint64 counter_diff = media_stream_counter -
        last_media_stream_counter_;
    if (counter_diff > 0 && timebase > last_timebase_)
      last_good_interval_ = timebase_diff / counter_diff;
  }
  if (last_good_interval_.InMicroseconds() < kMinVsyncIntervalUs ||
      last_good_interval_.InMicroseconds() > kMaxVsyncIntervalUs) {
    LOG(FATAL) << "Calculated bogus refresh interval of "
               << last_good_interval_.InMicroseconds() << " us.";
  }

  last_timebase_ = timebase;
  last_media_stream_counter_ = media_stream_counter;
  callback.Run(timebase, last_good_interval_);
#endif  // defined(OS_LINUX)
}

}  // namespace gfx
<|endoftext|>


<commit_before>/*
 * CoreWrapper.cpp
 *
 *  Created on: 2 févr. 2010
 *      Author: labm2414
 */

#include "CoreWrapper.h"
#include <ros/ros.h>
#include <sensor_msgs/Image.h>
#include <sensor_msgs/image_encodings.h>
#include <cv_bridge/cv_bridge.h>
#include <rtabmap/core/RtabmapEvent.h>
#include <rtabmap/core/Rtabmap.h>
#include <rtabmap/core/Camera.h>
#include <rtabmap/core/Parameters.h>
#include <rtabmap/utilite/UEventsManager.h>
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UFile.h>
#include <rtabmap/utilite/UStl.h>
#include <rtabmap/utilite/UConversion.h>
#include <opencv2/highgui/highgui.hpp>

//msgs
#include "rtabmap/Info.h"
#include "rtabmap/InfoEx.h"

using namespace rtabmap;

CoreWrapper::CoreWrapper(bool deleteDbOnStart) :
		rtabmap_(0),
		configPath_(UDirectory::homeDir()+"/.rtabmap/rtabmap.ini")
{
	ros::NodeHandle nh("~");
	infoPub_ = nh.advertise<rtabmap::Info>("info", 1);
	infoPubEx_ = nh.advertise<rtabmap::InfoEx>("infoEx", 1);
	parametersLoadedPub_ = nh.advertise<std_msgs::Empty>("parameters_loaded", 1);

	rtabmap_ = new Rtabmap();

	std::string workingDir = UDirectory::homeDir()+"/.rtabmap";
	nh.param("config_path", configPath_, configPath_);
	nh.param("working_directory", workingDir, workingDir);

	configPath_ = uReplaceChar(configPath_, '~', UDirectory::homeDir());
	workingDir = uReplaceChar(workingDir, '~', UDirectory::homeDir());

	loadNodeParameters(configPath_, workingDir);

	rtabmap_->init(configPath_, deleteDbOnStart);

	resetMemorySrv_ = nh.advertiseService("resetMemory", &CoreWrapper::resetMemoryCallback, this);
	dumpMemorySrv_ = nh.advertiseService("dumpMemory", &CoreWrapper::dumpMemoryCallback, this);
	deleteMemorySrv_ = nh.advertiseService("deleteMemory", &CoreWrapper::deleteMemoryCallback, this);
	dumpPredictionSrv_ = nh.advertiseService("dumpPrediction", &CoreWrapper::dumpPredictionCallback, this);

	nh = ros::NodeHandle();
	parametersUpdatedTopic_ = nh.subscribe("rtabmap_gui/parameters_updated", 1, &CoreWrapper::parametersUpdatedCallback, this);

	image_transport::ImageTransport it(nh);
	imageTopic_ = it.subscribe("image", 1, &CoreWrapper::imageReceivedCallback, this);
}

CoreWrapper::~CoreWrapper()
{
	this->saveNodeParameters(configPath_);
	delete rtabmap_;
}

ParametersMap CoreWrapper::loadNodeParameters(const std::string & configFile,
											  const std::string & workingDirectory)
{
	ROS_INFO("Loading parameters from %s", configFile.c_str());
	if(!UFile::exists(configFile.c_str()))
	{
		ROS_WARN("Config file doesn't exist! It will be generated...");
	}

	ParametersMap parameters = Parameters::getDefaultParameters();
	Rtabmap::readParameters(configFile.c_str(), parameters);

	if(workingDirectory.size())
	{
		parameters.at(Parameters::kRtabmapWorkingDirectory()) = workingDirectory;
	}

	ros::NodeHandle nh("~");
	for(ParametersMap::const_iterator i=parameters.begin(); i!=parameters.end(); ++i)
	{
		nh.setParam(i->first, i->second);
	}
	parametersLoadedPub_.publish(std_msgs::Empty());
	return parameters;
}

void CoreWrapper::saveNodeParameters(const std::string & configFile)
{
	printf("Saving parameters to %s\n", configFile.c_str());

	if(!UFile::exists(configFile.c_str()))
	{
		printf("Config file doesn't exist, a new one will be created.\n");
	}

	ParametersMap parameters = Parameters::getDefaultParameters();
	ros::NodeHandle nh("~");
	for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
	{
		std::string value;
		if(nh.getParam(iter->first,value))
		{
			iter->second = value;
		}
	}

	Rtabmap::writeParameters(configFile.c_str(), parameters);

	std::string databasePath = parameters.at(Parameters::kRtabmapWorkingDirectory())+"/rtabmap.db";
	printf("Saving database/long-term memory... (located at %s)\n", databasePath.c_str());
}

void CoreWrapper::imageReceivedCallback(const sensor_msgs::ImageConstPtr & msg)
{
	if(msg->data.size())
	{
		//ROS_INFO("Received image.");
		cv_bridge::CvImageConstPtr ptr = cv_bridge::toCvShare(msg);
		rtabmap_->process(ptr->image, ptr->header.seq);
		const Statistics & stats = rtabmap_->getStatistics();
		this->publishStats(stats);
	}
}

bool CoreWrapper::resetMemoryCallback(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
	rtabmap_->resetMemory();
	return true;
}

bool CoreWrapper::dumpMemoryCallback(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
	rtabmap_->dumpData();
	return true;
}

bool CoreWrapper::deleteMemoryCallback(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
	rtabmap_->resetMemory(true);
	return true;
}

bool CoreWrapper::dumpPredictionCallback(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
	rtabmap_->dumpPrediction();
	return true;
}

void CoreWrapper::parametersUpdatedCallback(const std_msgs::EmptyConstPtr & msg)
{
	rtabmap::ParametersMap parameters = rtabmap::Parameters::getDefaultParameters();
	ros::NodeHandle nh("~");
	for(rtabmap::ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
	{
		std::string value;
		if(nh.getParam(iter->first, value))
		{
			iter->second = value;
		}
	}
	ROS_INFO("Updating parameters");
	rtabmap_->parseParameters(parameters);
}

void CoreWrapper::publishStats(const Statistics & stats)
{
	if(infoPub_.getNumSubscribers() || infoPubEx_.getNumSubscribers())
	{
		if(infoPub_.getNumSubscribers())
		{
			//ROS_INFO("Sending RtabmapInfo msg (last_id=%d)...", stat.refImageId());
			rtabmap::InfoPtr msg(new rtabmap::Info);
			msg->refId = stats.refImageId();
			msg->loopClosureId = stats.loopClosureId();
			infoPub_.publish(msg);
		}

		if(infoPubEx_.getNumSubscribers())
		{
			//ROS_INFO("Sending infoEx msg (last_id=%d)...", stat.refImageId());
			rtabmap::InfoExPtr msg(new rtabmap::InfoEx);
			msg->refId = stats.refImageId();
			msg->loopClosureId = stats.loopClosureId();

			// Detailed info
			if(stats.extended())
			{
				if(!stats.refImage().empty())
				{
					// compress (the gui would work on a remote computer, this on the robot)
					cv::imencode(".png", stats.refImage(), msg->refImage);

					/*
					cv_bridge::CvImage img;
					if(stats.refImage().channels() == 1)
					{
						img.encoding = sensor_msgs::image_encodings::MONO8;
					}
					else
					{
						img.encoding = sensor_msgs::image_encodings::BGR8;
					}
					img.image = stats.refImage();
					sensor_msgs::ImagePtr rosMsg = img.toImageMsg();
					rosMsg->header.frame_id = "camera";
					rosMsg->header.stamp = ros::Time::now();
					msg->refImage = *rosMsg;
					*/
				}
				if(!stats.loopImage().empty())
				{
					// compress (the gui would work on a remote computer, this on the robot)
					cv::imencode(".png", stats.loopImage(), msg->loopImage);

					/*
					cv_bridge::CvImage img;
					if(stats.loopImage().channels() == 1)
					{
						img.encoding = sensor_msgs::image_encodings::MONO8;
					}
					else
					{
						img.encoding = sensor_msgs::image_encodings::BGR8;
					}
					img.image = stats.loopImage();
					sensor_msgs::ImagePtr rosMsg = img.toImageMsg();
					rosMsg->header.frame_id = "camera";
					rosMsg->header.stamp = ros::Time::now();
					msg->loopImage = *rosMsg;
					*/
				}

				//Posterior, likelihood, childCount
				msg->posteriorKeys = uKeys(stats.posterior());
				msg->posteriorValues = uValues(stats.posterior());
				msg->likelihoodKeys = uKeys(stats.likelihood());
				msg->likelihoodValues = uValues(stats.likelihood());
				msg->rawLikelihoodKeys = uKeys(stats.rawLikelihood());
				msg->rawLikelihoodValues = uValues(stats.rawLikelihood());
				msg->weightsKeys = uKeys(stats.weights());
				msg->weightsValues = uValues(stats.weights());

				//Features stuff...
				msg->refWordsKeys = uKeys(stats.refWords());
				msg->refWordsValues = std::vector<rtabmap::KeyPoint>(stats.refWords().size());
				int index = 0;
				for(std::multimap<int, cv::KeyPoint>::const_iterator i=stats.refWords().begin();
					i!=stats.refWords().end();
					++i)
				{
					msg->refWordsValues.at(index).angle = i->second.angle;
					msg->refWordsValues.at(index).response = i->second.response;
					msg->refWordsValues.at(index).ptx = i->second.pt.x;
					msg->refWordsValues.at(index).pty = i->second.pt.y;
					msg->refWordsValues.at(index).size = i->second.size;
					msg->refWordsValues.at(index).octave = i->second.octave;
					msg->refWordsValues.at(index).class_id = i->second.class_id;
					++index;
				}

				msg->loopWordsKeys = uKeys(stats.loopWords());
				msg->loopWordsValues = std::vector<rtabmap::KeyPoint>(stats.loopWords().size());
				index = 0;
				for(std::multimap<int, cv::KeyPoint>::const_iterator i=stats.loopWords().begin();
					i!=stats.loopWords().end();
					++i)
				{
					msg->loopWordsValues.at(index).angle = i->second.angle;
					msg->loopWordsValues.at(index).response = i->second.response;
					msg->loopWordsValues.at(index).ptx = i->second.pt.x;
					msg->loopWordsValues.at(index).pty = i->second.pt.y;
					msg->loopWordsValues.at(index).size = i->second.size;
					msg->loopWordsValues.at(index).octave = i->second.octave;
					msg->loopWordsValues.at(index).class_id = i->second.class_id;
					++index;
				}

				// Statistics data
				msg->statsKeys = uKeys(stats.data());
				msg->statsValues = uValues(stats.data());
			}
			infoPubEx_.publish(msg);
		}
	}
}
<commit_msg>ros-pkg: don't use anymore image sequence from the ros msg received (fixed ids bug when restarting rtabmap with an existing database)<commit_after>/*
 * CoreWrapper.cpp
 *
 *  Created on: 2 févr. 2010
 *      Author: labm2414
 */

#include "CoreWrapper.h"
#include <ros/ros.h>
#include <sensor_msgs/Image.h>
#include <sensor_msgs/image_encodings.h>
#include <cv_bridge/cv_bridge.h>
#include <rtabmap/core/RtabmapEvent.h>
#include <rtabmap/core/Rtabmap.h>
#include <rtabmap/core/Camera.h>
#include <rtabmap/core/Parameters.h>
#include <rtabmap/utilite/UEventsManager.h>
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UFile.h>
#include <rtabmap/utilite/UStl.h>
#include <rtabmap/utilite/UConversion.h>
#include <opencv2/highgui/highgui.hpp>

//msgs
#include "rtabmap/Info.h"
#include "rtabmap/InfoEx.h"

using namespace rtabmap;

CoreWrapper::CoreWrapper(bool deleteDbOnStart) :
		rtabmap_(0),
		configPath_(UDirectory::homeDir()+"/.rtabmap/rtabmap.ini")
{
	ros::NodeHandle nh("~");
	infoPub_ = nh.advertise<rtabmap::Info>("info", 1);
	infoPubEx_ = nh.advertise<rtabmap::InfoEx>("infoEx", 1);
	parametersLoadedPub_ = nh.advertise<std_msgs::Empty>("parameters_loaded", 1);

	rtabmap_ = new Rtabmap();

	std::string workingDir = UDirectory::homeDir()+"/.rtabmap";
	nh.param("config_path", configPath_, configPath_);
	nh.param("working_directory", workingDir, workingDir);

	configPath_ = uReplaceChar(configPath_, '~', UDirectory::homeDir());
	workingDir = uReplaceChar(workingDir, '~', UDirectory::homeDir());

	loadNodeParameters(configPath_, workingDir);

	rtabmap_->init(configPath_, deleteDbOnStart);

	resetMemorySrv_ = nh.advertiseService("resetMemory", &CoreWrapper::resetMemoryCallback, this);
	dumpMemorySrv_ = nh.advertiseService("dumpMemory", &CoreWrapper::dumpMemoryCallback, this);
	deleteMemorySrv_ = nh.advertiseService("deleteMemory", &CoreWrapper::deleteMemoryCallback, this);
	dumpPredictionSrv_ = nh.advertiseService("dumpPrediction", &CoreWrapper::dumpPredictionCallback, this);

	nh = ros::NodeHandle();
	parametersUpdatedTopic_ = nh.subscribe("rtabmap_gui/parameters_updated", 1, &CoreWrapper::parametersUpdatedCallback, this);

	image_transport::ImageTransport it(nh);
	imageTopic_ = it.subscribe("image", 1, &CoreWrapper::imageReceivedCallback, this);
}

CoreWrapper::~CoreWrapper()
{
	this->saveNodeParameters(configPath_);
	delete rtabmap_;
}

ParametersMap CoreWrapper::loadNodeParameters(const std::string & configFile,
											  const std::string & workingDirectory)
{
	ROS_INFO("Loading parameters from %s", configFile.c_str());
	if(!UFile::exists(configFile.c_str()))
	{
		ROS_WARN("Config file doesn't exist! It will be generated...");
	}

	ParametersMap parameters = Parameters::getDefaultParameters();
	Rtabmap::readParameters(configFile.c_str(), parameters);

	if(workingDirectory.size())
	{
		parameters.at(Parameters::kRtabmapWorkingDirectory()) = workingDirectory;
	}

	ros::NodeHandle nh("~");
	for(ParametersMap::const_iterator i=parameters.begin(); i!=parameters.end(); ++i)
	{
		nh.setParam(i->first, i->second);
	}
	parametersLoadedPub_.publish(std_msgs::Empty());
	return parameters;
}

void CoreWrapper::saveNodeParameters(const std::string & configFile)
{
	printf("Saving parameters to %s\n", configFile.c_str());

	if(!UFile::exists(configFile.c_str()))
	{
		printf("Config file doesn't exist, a new one will be created.\n");
	}

	ParametersMap parameters = Parameters::getDefaultParameters();
	ros::NodeHandle nh("~");
	for(ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
	{
		std::string value;
		if(nh.getParam(iter->first,value))
		{
			iter->second = value;
		}
	}

	Rtabmap::writeParameters(configFile.c_str(), parameters);

	std::string databasePath = parameters.at(Parameters::kRtabmapWorkingDirectory())+"/rtabmap.db";
	printf("Saving database/long-term memory... (located at %s)\n", databasePath.c_str());
}

void CoreWrapper::imageReceivedCallback(const sensor_msgs::ImageConstPtr & msg)
{
	if(msg->data.size())
	{
		//ROS_INFO("Received image.");
		cv_bridge::CvImageConstPtr ptr = cv_bridge::toCvShare(msg);
		rtabmap_->process(ptr->image);
		const Statistics & stats = rtabmap_->getStatistics();
		this->publishStats(stats);
	}
}

bool CoreWrapper::resetMemoryCallback(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
	rtabmap_->resetMemory();
	return true;
}

bool CoreWrapper::dumpMemoryCallback(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
	rtabmap_->dumpData();
	return true;
}

bool CoreWrapper::deleteMemoryCallback(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
	rtabmap_->resetMemory(true);
	return true;
}

bool CoreWrapper::dumpPredictionCallback(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
	rtabmap_->dumpPrediction();
	return true;
}

void CoreWrapper::parametersUpdatedCallback(const std_msgs::EmptyConstPtr & msg)
{
	rtabmap::ParametersMap parameters = rtabmap::Parameters::getDefaultParameters();
	ros::NodeHandle nh("~");
	for(rtabmap::ParametersMap::iterator iter=parameters.begin(); iter!=parameters.end(); ++iter)
	{
		std::string value;
		if(nh.getParam(iter->first, value))
		{
			iter->second = value;
		}
	}
	ROS_INFO("Updating parameters");
	rtabmap_->parseParameters(parameters);
}

void CoreWrapper::publishStats(const Statistics & stats)
{
	if(infoPub_.getNumSubscribers() || infoPubEx_.getNumSubscribers())
	{
		if(infoPub_.getNumSubscribers())
		{
			//ROS_INFO("Sending RtabmapInfo msg (last_id=%d)...", stat.refImageId());
			rtabmap::InfoPtr msg(new rtabmap::Info);
			msg->refId = stats.refImageId();
			msg->loopClosureId = stats.loopClosureId();
			infoPub_.publish(msg);
		}

		if(infoPubEx_.getNumSubscribers())
		{
			//ROS_INFO("Sending infoEx msg (last_id=%d)...", stat.refImageId());
			rtabmap::InfoExPtr msg(new rtabmap::InfoEx);
			msg->refId = stats.refImageId();
			msg->loopClosureId = stats.loopClosureId();

			// Detailed info
			if(stats.extended())
			{
				if(!stats.refImage().empty())
				{
					// compress (the gui would work on a remote computer, this on the robot)
					cv::imencode(".png", stats.refImage(), msg->refImage);

					/*
					cv_bridge::CvImage img;
					if(stats.refImage().channels() == 1)
					{
						img.encoding = sensor_msgs::image_encodings::MONO8;
					}
					else
					{
						img.encoding = sensor_msgs::image_encodings::BGR8;
					}
					img.image = stats.refImage();
					sensor_msgs::ImagePtr rosMsg = img.toImageMsg();
					rosMsg->header.frame_id = "camera";
					rosMsg->header.stamp = ros::Time::now();
					msg->refImage = *rosMsg;
					*/
				}
				if(!stats.loopImage().empty())
				{
					// compress (the gui would work on a remote computer, this on the robot)
					cv::imencode(".png", stats.loopImage(), msg->loopImage);

					/*
					cv_bridge::CvImage img;
					if(stats.loopImage().channels() == 1)
					{
						img.encoding = sensor_msgs::image_encodings::MONO8;
					}
					else
					{
						img.encoding = sensor_msgs::image_encodings::BGR8;
					}
					img.image = stats.loopImage();
					sensor_msgs::ImagePtr rosMsg = img.toImageMsg();
					rosMsg->header.frame_id = "camera";
					rosMsg->header.stamp = ros::Time::now();
					msg->loopImage = *rosMsg;
					*/
				}

				//Posterior, likelihood, childCount
				msg->posteriorKeys = uKeys(stats.posterior());
				msg->posteriorValues = uValues(stats.posterior());
				msg->likelihoodKeys = uKeys(stats.likelihood());
				msg->likelihoodValues = uValues(stats.likelihood());
				msg->rawLikelihoodKeys = uKeys(stats.rawLikelihood());
				msg->rawLikelihoodValues = uValues(stats.rawLikelihood());
				msg->weightsKeys = uKeys(stats.weights());
				msg->weightsValues = uValues(stats.weights());

				//Features stuff...
				msg->refWordsKeys = uKeys(stats.refWords());
				msg->refWordsValues = std::vector<rtabmap::KeyPoint>(stats.refWords().size());
				int index = 0;
				for(std::multimap<int, cv::KeyPoint>::const_iterator i=stats.refWords().begin();
					i!=stats.refWords().end();
					++i)
				{
					msg->refWordsValues.at(index).angle = i->second.angle;
					msg->refWordsValues.at(index).response = i->second.response;
					msg->refWordsValues.at(index).ptx = i->second.pt.x;
					msg->refWordsValues.at(index).pty = i->second.pt.y;
					msg->refWordsValues.at(index).size = i->second.size;
					msg->refWordsValues.at(index).octave = i->second.octave;
					msg->refWordsValues.at(index).class_id = i->second.class_id;
					++index;
				}

				msg->loopWordsKeys = uKeys(stats.loopWords());
				msg->loopWordsValues = std::vector<rtabmap::KeyPoint>(stats.loopWords().size());
				index = 0;
				for(std::multimap<int, cv::KeyPoint>::const_iterator i=stats.loopWords().begin();
					i!=stats.loopWords().end();
					++i)
				{
					msg->loopWordsValues.at(index).angle = i->second.angle;
					msg->loopWordsValues.at(index).response = i->second.response;
					msg->loopWordsValues.at(index).ptx = i->second.pt.x;
					msg->loopWordsValues.at(index).pty = i->second.pt.y;
					msg->loopWordsValues.at(index).size = i->second.size;
					msg->loopWordsValues.at(index).octave = i->second.octave;
					msg->loopWordsValues.at(index).class_id = i->second.class_id;
					++index;
				}

				// Statistics data
				msg->statsKeys = uKeys(stats.data());
				msg->statsValues = uValues(stats.data());
			}
			infoPubEx_.publish(msg);
		}
	}
}
<|endoftext|>


<commit_before>// The K3 Runtime Collections Library.
//
// This file contains definitions for the various operations performed on K3 collections, used by
// the generated C++ code. The C++ realizations of K3 Collections will inherit from the
// K3::Collection class, providing a suitable content type.
//
// TODO:
//  - Use <algorithm> routines to perform collection transformations? In particular, investigate
//    order-of-operations semantics.
//  - Use container agnostic mutation operations?
//  - Use bulk mutation operations (iterator-based insertion, for example)?
//  - Optimize all the unnecessary copies, using std::move?
#ifndef K3_RUNTIME_COLLECTIONS_H
#define K3_RUNTIME_COLLECTIONS_H

#include <functional>
#include <list>
#include <map>
#include <memory>
#include <tuple>

#include <Engine.hpp>
#include <dataspace/StlDS.hpp>
#include <dataspace/SetDS.hpp>
#include <dataspace/ListDS.hpp>
#include <dataspace/SortedDS.hpp>
#include <boost/serialization/base_object.hpp>

namespace K3 {
  template <template <class...> class D, class E>
  class Collection: public D<E> {
    public:
      Collection(Engine * e) : D<E>(e) {};

      template <template <class> class F>
      Collection(const Collection<F, E> other) : D<E>(other)  {}

      template <template <class> class F>
      Collection(Collection<F, E>&& other) : D<E>(other) {}

      Collection(D<E> other) : D<E>(other) {}

      // TODO: shared_ptr vs. value?
      std::shared_ptr<E> peek() { return D<E>::peek(); }

      void insert(const E& elem) { D<E>::insert(elem); }
      //void insert(E&& elem) { D<E>::insert(elem); }

      void erase(const E& elem)  { D<E>::erase(elem); }

      void update(const E& v1, const E& v2) { D<E>::update(v1,v2); }
      void update(const E& v1, E&& v2) { D<E>::update(v1,v2); }

      std::tuple<Collection<D, E>, Collection<D, E>> split() {
        auto tup = D<E>::split();
        D<E> ds1 = get<0>(tup);
        D<E> ds2 = get<1>(tup);
        return std::make_tuple(Collection<D,E>(ds1), Collection<D,E>(ds2));
      }

      template <template <class> class F>
      Collection<D, E> combine(const Collection<F, E>& other) {
       return Collection<D,E>(D<E>::combine(other));
      }

      template <class T>
      Collection<D, T> map(std::function<T(E)> f) {
       return Collection<D,T>(D<E>::map(f));
      }

      Collection<D, E> filter(std::function<bool(E)> f) {
       return Collection<D,E>(D<E>::filter(f));
      }

      template <class Z>
      Z fold(std::function<Z(Z, E)> f, Z init) {
       return D<E>::fold(f, init);
      }

      template <class K, class Z>
      Collection<D, std::tuple<K, Z>> group_by(
        std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
          // Create a map to hold partial results
          std::map<K, Z> accs = std::map<K,Z>();
          // lambda to apply to each element
          std::function<void(E)> f = [&] (E elem) {
            K key = grouper(elem);
            if (accs.find(key) == accs.end()) {
              accs[key] = init;
            }
            accs[key] = folder(accs[key], elem);
          };
          D<E>::iterate(f);
          // Build Collection result
          Collection<D, std::tuple<K,Z>> result = Collection<D,std::tuple<K,Z>>(D<E>::getEngine());
          typename std::map<K,Z>::iterator it;
          for (it = accs.begin(); it != accs.end(); ++it) {
            std::tuple<K,Z> tup = std::make_tuple(it->first, it->second);
            result.insert(tup);
          }
         return result;
      }

      template <template <class> class F, class T>
      Collection<D, T> ext(std::function<Collection<F, T>(E)> expand) {
        Collection<D, T> result = Collection<D,T>(D<E>::getEngine());
        auto add_to_result = [&] (T elem) {result.insert(elem); };
        auto fun = [&] (E elem) {
          expand(elem).iterate(add_to_result);
        };
        D<E>::iterate(fun);
        return result;
      }

  private:
    friend class boost::serialization::access;
    // Serialize a collection by serializing its base-class (a dataspace)
    template<class Archive>
    void serialize(Archive &ar, const unsigned int version) {
      ar & boost::serialization::base_object<D<E>>(*this);
    }

  };

  template <typename E>
  // TODO: make this more generic? ie a SeqDS interface
  class Seq : public Collection<ListDS, E> {
    typedef Collection<ListDS, E> super;
     public:
      Seq(Engine * e) : super(e) {};

      Seq(const Seq<E>& other) : super(other)  {}

      Seq(super other) : super(other) {}

      // Convert from Collection<ListDS, E> to Seq<E>
      std::tuple<Seq<E>, Seq<E>> split() {
        auto tup = super::split();
        super ds1 = get<0>(tup);
        super ds2 = get<1>(tup);
        return std::make_tuple(Seq<E>(ds1), Seq<E>(ds2));
      }

      Seq<E> combine(const Seq<E>& other) {
       return Seq<E>(super::combine(other));
      }

      template <class T>
      Seq<T> map(std::function<T(E)> f) {
       return Seq<T>(super::map(f));
      }

      Seq<E> filter(std::function<bool(E)> f) {
       return Seq<E>(super::filter(f));
      }

      Seq<E> sort(std::function<int(E,E)> f) {
        super s = super(ListDS<E>::sort(f));
        return Seq<E>(s);

      }

      template <class K, class Z>
      Seq<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<ListDS, std::tuple<K,Z>> s = super::group_by(grouper,folder,init);
        return Seq<std::tuple<K,Z>>(s);
      }

      template <class T>
      Seq<T> ext(std::function<Collection<ListDS, T>(E)> expand) {
        Collection<ListDS, T> result = super::ext(expand);
        return Seq<T>(result);
      }
  };

  template <typename E>
  // TODO: make this more generic? ie a SetDS interface
  class Set : public Collection<SetDS, E> {
    typedef Collection<SetDS, E> super;
    typedef SetDS<E> dataspace;
     public:
      Set(Engine * e) : super(e) {};

      Set(const Set<E>& other) : super(other)  {}

      Set(super other) : super(other) {}

      // Convert from Collection<ListDS, E> to Set<E>
      std::tuple<Set<E>, Set<E>> split() {
        auto tup = super::split();
        super ds1 = get<0>(tup);
        super ds2 = get<1>(tup);
        return std::make_tuple(Set<E>(ds1), Set<E>(ds2));
      }

      Set<E> combine(const Set<E>& other) {
       return Set<E>(super::combine(other));
      }

      template <class T>
      Set<T> map(std::function<T(E)> f) {
       return Set<T>(super::map(f));
      }

      Set<E> filter(std::function<bool(E)> f) {
       return Set<E>(super::filter(f));
      }

      template <class K, class Z>
      Set<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<SetDS, std::tuple<K,Z>> s = super::group_by(grouper,folder,init);
        return Set<std::tuple<K,Z>>(s);
      }

      template <class T>
      Set<T> ext(std::function<Collection<SetDS, T>(E)> expand) {
        Collection<SetDS, T> result = super::ext(expand);
        return Set<T>(result);
      }

      bool member(E e) {
        return dataspace::member(e);
      }

      bool isSubsetOf(SetDS<E> other) {
        return dataspace::isSubsetOf(other);
      }

      // TODO union is a reserved word
      Set union1(Set<E> other) {
        super s = super(dataspace::union1(other));
        return Set<E>(s);
      }

      Set intersect(Set<E> other) {
        super s = super(dataspace::intersect(other));
        return Set<E>(s);
      }

      Set difference(Set<E> other) {
        super s = super(dataspace::difference(other));
        return Set<E>(s);
      }

  };

  template <typename E>
  class Sorted : public Collection<SortedDS, E> {
    typedef Collection<SortedDS, E> super;
    typedef SortedDS<E> dataspace;
     public:
      Sorted(Engine * e) : super(e) {};

      Sorted(const Sorted<E>& other) : super(other)  {}

      Sorted(super other) : super(other) {}

      // Convert from Collection<ListDS, E> to Sorted<E>
      std::tuple<Sorted<E>, Sorted<E>> split() {
        auto tup = super::split();
        super ds1 = get<0>(tup);
        super ds2 = get<1>(tup);
        return std::make_tuple(Sorted<E>(ds1), Sorted<E>(ds2));
      }

      Sorted<E> combine(const Sorted<E>& other) {
       return Sorted<E>(super::combine(other));
      }

      template <class T>
      Sorted<T> map(std::function<T(E)> f) {
       return Sorted<T>(super::map(f));
      }

      Sorted<E> filter(std::function<bool(E)> f) {
       return Sorted<E>(super::filter(f));
      }

      template <class K, class Z>
      Sorted<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<SortedDS, std::tuple<K,Z>> s = super::group_by(grouper,folder,init);
        return Sorted<std::tuple<K,Z>>(s);
      }

      template <class T>
      Sorted<T> ext(std::function<Collection<SortedDS, T>(E)> expand) {
        Collection<SortedDS, T> result = super::ext(expand);
        return Sorted<T>(result);
      }

      shared_ptr<E> min() { return dataspace::min(); }

      shared_ptr<E> max() { return dataspace::max(); }

      shared_ptr<E> lowerBound(E a) { return dataspace::lowerBound(a); }

      shared_ptr<E> upperBound(E a) { return dataspace::lowerBound(a); }

      Sorted<E> slice(E a, E b) {
        super s = super(dataspace::slice(a,b));
        return Sorted<E>(s);
      }

  };
}

#endif
<commit_msg>Uncomment line<commit_after>// The K3 Runtime Collections Library.
//
// This file contains definitions for the various operations performed on K3 collections, used by
// the generated C++ code. The C++ realizations of K3 Collections will inherit from the
// K3::Collection class, providing a suitable content type.
//
// TODO:
//  - Use <algorithm> routines to perform collection transformations? In particular, investigate
//    order-of-operations semantics.
//  - Use container agnostic mutation operations?
//  - Use bulk mutation operations (iterator-based insertion, for example)?
//  - Optimize all the unnecessary copies, using std::move?
#ifndef K3_RUNTIME_COLLECTIONS_H
#define K3_RUNTIME_COLLECTIONS_H

#include <functional>
#include <list>
#include <map>
#include <memory>
#include <tuple>

#include <Engine.hpp>
#include <dataspace/StlDS.hpp>
#include <dataspace/SetDS.hpp>
#include <dataspace/ListDS.hpp>
#include <dataspace/SortedDS.hpp>
#include <boost/serialization/base_object.hpp>

namespace K3 {
  template <template <class...> class D, class E>
  class Collection: public D<E> {
    public:
      Collection(Engine * e) : D<E>(e) {};

      template <template <class> class F>
      Collection(const Collection<F, E> other) : D<E>(other)  {}

      template <template <class> class F>
      Collection(Collection<F, E>&& other) : D<E>(other) {}

      Collection(D<E> other) : D<E>(other) {}

      // TODO: shared_ptr vs. value?
      std::shared_ptr<E> peek() { return D<E>::peek(); }

      void insert(const E& elem) { D<E>::insert(elem); }
      void insert(E&& elem) { D<E>::insert(elem); }

      void erase(const E& elem)  { D<E>::erase(elem); }

      void update(const E& v1, const E& v2) { D<E>::update(v1,v2); }
      void update(const E& v1, E&& v2) { D<E>::update(v1,v2); }

      std::tuple<Collection<D, E>, Collection<D, E>> split() {
        auto tup = D<E>::split();
        D<E> ds1 = get<0>(tup);
        D<E> ds2 = get<1>(tup);
        return std::make_tuple(Collection<D,E>(ds1), Collection<D,E>(ds2));
      }

      template <template <class> class F>
      Collection<D, E> combine(const Collection<F, E>& other) {
       return Collection<D,E>(D<E>::combine(other));
      }

      template <class T>
      Collection<D, T> map(std::function<T(E)> f) {
       return Collection<D,T>(D<E>::map(f));
      }

      Collection<D, E> filter(std::function<bool(E)> f) {
       return Collection<D,E>(D<E>::filter(f));
      }

      template <class Z>
      Z fold(std::function<Z(Z, E)> f, Z init) {
       return D<E>::fold(f, init);
      }

      template <class K, class Z>
      Collection<D, std::tuple<K, Z>> group_by(
        std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
          // Create a map to hold partial results
          std::map<K, Z> accs = std::map<K,Z>();
          // lambda to apply to each element
          std::function<void(E)> f = [&] (E elem) {
            K key = grouper(elem);
            if (accs.find(key) == accs.end()) {
              accs[key] = init;
            }
            accs[key] = folder(accs[key], elem);
          };
          D<E>::iterate(f);
          // Build Collection result
          Collection<D, std::tuple<K,Z>> result = Collection<D,std::tuple<K,Z>>(D<E>::getEngine());
          typename std::map<K,Z>::iterator it;
          for (it = accs.begin(); it != accs.end(); ++it) {
            std::tuple<K,Z> tup = std::make_tuple(it->first, it->second);
            result.insert(tup);
          }
         return result;
      }

      template <template <class> class F, class T>
      Collection<D, T> ext(std::function<Collection<F, T>(E)> expand) {
        Collection<D, T> result = Collection<D,T>(D<E>::getEngine());
        auto add_to_result = [&] (T elem) {result.insert(elem); };
        auto fun = [&] (E elem) {
          expand(elem).iterate(add_to_result);
        };
        D<E>::iterate(fun);
        return result;
      }

  private:
    friend class boost::serialization::access;
    // Serialize a collection by serializing its base-class (a dataspace)
    template<class Archive>
    void serialize(Archive &ar, const unsigned int version) {
      ar & boost::serialization::base_object<D<E>>(*this);
    }

  };

  template <typename E>
  // TODO: make this more generic? ie a SeqDS interface
  class Seq : public Collection<ListDS, E> {
    typedef Collection<ListDS, E> super;
     public:
      Seq(Engine * e) : super(e) {};

      Seq(const Seq<E>& other) : super(other)  {}

      Seq(super other) : super(other) {}

      // Convert from Collection<ListDS, E> to Seq<E>
      std::tuple<Seq<E>, Seq<E>> split() {
        auto tup = super::split();
        super ds1 = get<0>(tup);
        super ds2 = get<1>(tup);
        return std::make_tuple(Seq<E>(ds1), Seq<E>(ds2));
      }

      Seq<E> combine(const Seq<E>& other) {
       return Seq<E>(super::combine(other));
      }

      template <class T>
      Seq<T> map(std::function<T(E)> f) {
       return Seq<T>(super::map(f));
      }

      Seq<E> filter(std::function<bool(E)> f) {
       return Seq<E>(super::filter(f));
      }

      Seq<E> sort(std::function<int(E,E)> f) {
        super s = super(ListDS<E>::sort(f));
        return Seq<E>(s);

      }

      template <class K, class Z>
      Seq<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<ListDS, std::tuple<K,Z>> s = super::group_by(grouper,folder,init);
        return Seq<std::tuple<K,Z>>(s);
      }

      template <class T>
      Seq<T> ext(std::function<Collection<ListDS, T>(E)> expand) {
        Collection<ListDS, T> result = super::ext(expand);
        return Seq<T>(result);
      }
  };

  template <typename E>
  // TODO: make this more generic? ie a SetDS interface
  class Set : public Collection<SetDS, E> {
    typedef Collection<SetDS, E> super;
    typedef SetDS<E> dataspace;
     public:
      Set(Engine * e) : super(e) {};

      Set(const Set<E>& other) : super(other)  {}

      Set(super other) : super(other) {}

      // Convert from Collection<ListDS, E> to Set<E>
      std::tuple<Set<E>, Set<E>> split() {
        auto tup = super::split();
        super ds1 = get<0>(tup);
        super ds2 = get<1>(tup);
        return std::make_tuple(Set<E>(ds1), Set<E>(ds2));
      }

      Set<E> combine(const Set<E>& other) {
       return Set<E>(super::combine(other));
      }

      template <class T>
      Set<T> map(std::function<T(E)> f) {
       return Set<T>(super::map(f));
      }

      Set<E> filter(std::function<bool(E)> f) {
       return Set<E>(super::filter(f));
      }

      template <class K, class Z>
      Set<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<SetDS, std::tuple<K,Z>> s = super::group_by(grouper,folder,init);
        return Set<std::tuple<K,Z>>(s);
      }

      template <class T>
      Set<T> ext(std::function<Collection<SetDS, T>(E)> expand) {
        Collection<SetDS, T> result = super::ext(expand);
        return Set<T>(result);
      }

      bool member(E e) {
        return dataspace::member(e);
      }

      bool isSubsetOf(SetDS<E> other) {
        return dataspace::isSubsetOf(other);
      }

      // TODO union is a reserved word
      Set union1(Set<E> other) {
        super s = super(dataspace::union1(other));
        return Set<E>(s);
      }

      Set intersect(Set<E> other) {
        super s = super(dataspace::intersect(other));
        return Set<E>(s);
      }

      Set difference(Set<E> other) {
        super s = super(dataspace::difference(other));
        return Set<E>(s);
      }

  };

  template <typename E>
  class Sorted : public Collection<SortedDS, E> {
    typedef Collection<SortedDS, E> super;
    typedef SortedDS<E> dataspace;
     public:
      Sorted(Engine * e) : super(e) {};

      Sorted(const Sorted<E>& other) : super(other)  {}

      Sorted(super other) : super(other) {}

      // Convert from Collection<ListDS, E> to Sorted<E>
      std::tuple<Sorted<E>, Sorted<E>> split() {
        auto tup = super::split();
        super ds1 = get<0>(tup);
        super ds2 = get<1>(tup);
        return std::make_tuple(Sorted<E>(ds1), Sorted<E>(ds2));
      }

      Sorted<E> combine(const Sorted<E>& other) {
       return Sorted<E>(super::combine(other));
      }

      template <class T>
      Sorted<T> map(std::function<T(E)> f) {
       return Sorted<T>(super::map(f));
      }

      Sorted<E> filter(std::function<bool(E)> f) {
       return Sorted<E>(super::filter(f));
      }

      template <class K, class Z>
      Sorted<std::tuple<K, Z>> group_by
      (std::function<K(E)> grouper, std::function<Z(Z, E)> folder, Z init) {
        Collection<SortedDS, std::tuple<K,Z>> s = super::group_by(grouper,folder,init);
        return Sorted<std::tuple<K,Z>>(s);
      }

      template <class T>
      Sorted<T> ext(std::function<Collection<SortedDS, T>(E)> expand) {
        Collection<SortedDS, T> result = super::ext(expand);
        return Sorted<T>(result);
      }

      shared_ptr<E> min() { return dataspace::min(); }

      shared_ptr<E> max() { return dataspace::max(); }

      shared_ptr<E> lowerBound(E a) { return dataspace::lowerBound(a); }

      shared_ptr<E> upperBound(E a) { return dataspace::lowerBound(a); }

      Sorted<E> slice(E a, E b) {
        super s = super(dataspace::slice(a,b));
        return Sorted<E>(s);
      }

  };
}

#endif
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
// BSD 3-Clause License
//
// Copyright (c) 2022, The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include <numeric>
#include <string>

#include "db.h"
#include "util.h"
#include "utl/Logger.h"

namespace odb {

using std::string;
using std::vector;

static void buildRow(dbBlock* block,
                     const string& name,
                     dbSite* site,
                     int start_x,
                     int end_x,
                     int y,
                     dbOrientType& orient,
                     dbRowDir& direction,
                     int min_row_width)
{
  const int site_width = site->getWidth();
  const int new_row_num_sites = (end_x - start_x) / site_width;
  const int new_row_width = new_row_num_sites * site_width;

  if (new_row_num_sites > 0 && new_row_width >= min_row_width) {
    dbRow::create(block,
                  name.c_str(),
                  site,
                  start_x,
                  y,
                  orient,
                  direction,
                  new_row_num_sites,
                  site_width);
  }
}

static void cutRow(dbBlock* block,
                   dbRow* row,
                   vector<dbBox*>& row_blockages,
                   int min_row_width,
                   int halo_x,
                   int halo_y)
{
  string row_name = row->getName();
  Rect row_bb = row->getBBox();

  dbSite* row_site = row->getSite();
  const int site_width = row_site->getWidth();
  dbOrientType orient = row->getOrient();
  dbRowDir direction = row->getDirection();

  const int curr_min_row_width = min_row_width + 2 * site_width;

  vector<dbBox*> row_blockage_bboxs = row_blockages;
  vector<std::pair<int, int>> row_blockage_xs;
  for (dbBox* row_blockage_bbox : row_blockages) {
    row_blockage_xs.push_back(
        std::make_pair(row_blockage_bbox->xMin(), row_blockage_bbox->xMax()));
  }

  std::sort(row_blockage_xs.begin(), row_blockage_xs.end());

  int start_origin_x = row_bb.xMin();
  int start_origin_y = row_bb.yMin();
  int row_sub_idx = 1;
  for (std::pair<int, int> blockage : row_blockage_xs) {
    const int blockage_x0 = blockage.first;
    const int new_row_end_x
        = makeSiteLoc(blockage_x0 - halo_x, site_width, 1, start_origin_x);
    buildRow(block,
             row_name + "_" + std::to_string(row_sub_idx),
             row_site,
             start_origin_x,
             new_row_end_x,
             start_origin_y,
             orient,
             direction,
             curr_min_row_width);
    row_sub_idx++;
    const int blockage_x1 = blockage.second;
    start_origin_x
        = makeSiteLoc(blockage_x1 + halo_x, site_width, 0, start_origin_x);
  }
  // Make last row
  buildRow(block,
           row_name + "_" + std::to_string(row_sub_idx),
           row_site,
           start_origin_x,
           row_bb.xMax(),
           start_origin_y,
           orient,
           direction,
           curr_min_row_width);
  // Remove current row
  dbRow::destroy(row);
}

static bool overlaps(dbBox* blockage, dbRow* row, int halo_x, int halo_y)
{
  Rect rowBB = row->getBBox();

  // Check if Y has overlap first since rows are long and skinny
  const int blockage_lly = blockage->yMin() - halo_y;
  const int blockage_ury = blockage->yMax() + halo_y;
  const int row_lly = rowBB.yMin();
  const int row_ury = rowBB.yMax();

  if (blockage_lly >= row_ury || row_lly >= blockage_ury) {
    return false;
  }

  const int blockage_llx = blockage->xMin() - halo_x;
  const int blockage_urx = blockage->xMax() + halo_x;
  const int row_llx = rowBB.xMin();
  const int row_urx = rowBB.xMax();

  if (blockage_llx >= row_urx || row_llx >= blockage_urx) {
    return false;
  }

  return true;
}

int makeSiteLoc(int x, double site_width, bool at_left_from_macro, int offset)
{
  double site_x = (x - offset) / site_width;
  int site_x1 = at_left_from_macro ? floor(site_x) : ceil(site_x);
  return site_x1 * site_width + offset;
}

void cutRows(dbBlock* block,
             const int min_row_width,
             const vector<dbBox*>& blockages,
             int halo_x,
             int halo_y,
             utl::Logger* logger)
{
  if (blockages.empty()) {
    return;
  }
  auto rows = block->getRows();
  const int initial_rows_count = rows.size();
  const int initial_sites_count
      = std::accumulate(rows.begin(), rows.end(), 0, [](int sum, dbRow* row) {
          return sum + row->getSiteCount();
        });

  // Gather rows needing to be cut up front
  vector<dbRow*> blocked_rows;
  std::map<dbRow*, vector<dbBox*>> row_blockages;
  for (dbBox* blockage : blockages) {
    for (dbRow* row : block->getRows()) {
      if (overlaps(blockage, row, halo_x, halo_y)) {
        if (row_blockages.find(row) == row_blockages.end()) {
          blocked_rows.push_back(row);
        }
        row_blockages[row].push_back(blockage);
      }
    }
  }

  // Cut rows around macros
  for (auto& [k, ignored] : row_blockages) {
    cutRow(block, k, row_blockages[k], min_row_width, halo_x, halo_y);
  }

  const int final_sites_count
      = std::accumulate(rows.begin(), rows.end(), 0, [](int sum, dbRow* row) {
          return sum + row->getSiteCount();
        });

  logger->info(utl::ODB,
               303,
               "The initial {} rows ({} sites) were cut with {} shapes for a "
               "total of {} rows ({} sites).",
               initial_rows_count,
               initial_sites_count,
               blockages.size(),
               block->getRows().size(),
               final_sites_count);
}

}  // namespace odb
<commit_msg>odb: update cutRows to consider new rows on every macro<commit_after>///////////////////////////////////////////////////////////////////////////////
// BSD 3-Clause License
//
// Copyright (c) 2022, The Regents of the University of California
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include <numeric>
#include <string>

#include "db.h"
#include "util.h"
#include "utl/Logger.h"

namespace odb {

using std::string;
using std::vector;

static void buildRow(dbBlock* block,
                     const string& name,
                     dbSite* site,
                     int start_x,
                     int end_x,
                     int y,
                     dbOrientType& orient,
                     dbRowDir& direction,
                     int min_row_width)
{
  const int site_width = site->getWidth();
  const int new_row_num_sites = (end_x - start_x) / site_width;
  const int new_row_width = new_row_num_sites * site_width;

  if (new_row_num_sites > 0 && new_row_width >= min_row_width) {
    dbRow::create(block,
                  name.c_str(),
                  site,
                  start_x,
                  y,
                  orient,
                  direction,
                  new_row_num_sites,
                  site_width);
  }
}

static void cutRow(dbBlock* block,
                   dbRow* row,
                   vector<dbBox*>& row_blockages,
                   int min_row_width,
                   int halo_x,
                   int halo_y)
{
  string row_name = row->getName();
  Rect row_bb = row->getBBox();

  dbSite* row_site = row->getSite();
  const int site_width = row_site->getWidth();
  dbOrientType orient = row->getOrient();
  dbRowDir direction = row->getDirection();

  const int curr_min_row_width = min_row_width + 2 * site_width;

  vector<dbBox*> row_blockage_bboxs = row_blockages;
  vector<std::pair<int, int>> row_blockage_xs;
  for (dbBox* row_blockage_bbox : row_blockages) {
    row_blockage_xs.push_back(
        std::make_pair(row_blockage_bbox->xMin(), row_blockage_bbox->xMax()));
  }

  std::sort(row_blockage_xs.begin(), row_blockage_xs.end());

  int start_origin_x = row_bb.xMin();
  int start_origin_y = row_bb.yMin();
  int row_sub_idx = 1;
  for (std::pair<int, int> blockage : row_blockage_xs) {
    const int blockage_x0 = blockage.first;
    const int new_row_end_x
        = makeSiteLoc(blockage_x0 - halo_x, site_width, 1, start_origin_x);
    buildRow(block,
             row_name + "_" + std::to_string(row_sub_idx),
             row_site,
             start_origin_x,
             new_row_end_x,
             start_origin_y,
             orient,
             direction,
             curr_min_row_width);
    row_sub_idx++;
    const int blockage_x1 = blockage.second;
    start_origin_x
        = makeSiteLoc(blockage_x1 + halo_x, site_width, 0, start_origin_x);
  }
  // Make last row
  buildRow(block,
           row_name + "_" + std::to_string(row_sub_idx),
           row_site,
           start_origin_x,
           row_bb.xMax(),
           start_origin_y,
           orient,
           direction,
           curr_min_row_width);
  // Remove current row
  dbRow::destroy(row);
}

static bool overlaps(dbBox* blockage, dbRow* row, int halo_x, int halo_y)
{
  Rect rowBB = row->getBBox();

  // Check if Y has overlap first since rows are long and skinny
  const int blockage_lly = blockage->yMin() - halo_y;
  const int blockage_ury = blockage->yMax() + halo_y;
  const int row_lly = rowBB.yMin();
  const int row_ury = rowBB.yMax();

  if (blockage_lly >= row_ury || row_lly >= blockage_ury) {
    return false;
  }

  const int blockage_llx = blockage->xMin() - halo_x;
  const int blockage_urx = blockage->xMax() + halo_x;
  const int row_llx = rowBB.xMin();
  const int row_urx = rowBB.xMax();

  if (blockage_llx >= row_urx || row_llx >= blockage_urx) {
    return false;
  }

  return true;
}

int makeSiteLoc(int x, double site_width, bool at_left_from_macro, int offset)
{
  double site_x = (x - offset) / site_width;
  int site_x1 = at_left_from_macro ? floor(site_x) : ceil(site_x);
  return site_x1 * site_width + offset;
}

void cutRows(dbBlock* block,
             const int min_row_width,
             const vector<dbBox*>& blockages,
             int halo_x,
             int halo_y,
             utl::Logger* logger)
{
  if (blockages.empty()) {
    return;
  }
  auto rows = block->getRows();
  const int initial_rows_count = rows.size();
  const int initial_sites_count
      = std::accumulate(rows.begin(), rows.end(), 0, [](int sum, dbRow* row) {
          return sum + row->getSiteCount();
        });

  // Gather rows needing to be cut up front
  for (dbBox* blockage : blockages) {
    std::map<dbRow*, vector<dbBox*>> row_blockages;
    for (dbRow* row : block->getRows()) {
      if (overlaps(blockage, row, halo_x, halo_y)) {
        row_blockages[row].push_back(blockage);
      }
    }
    // Cut rows around macros
    for (auto& [k, ignored] : row_blockages) {
      cutRow(block, k, row_blockages[k], min_row_width, halo_x, halo_y);
    }
  }

  const int final_sites_count
      = std::accumulate(rows.begin(), rows.end(), 0, [](int sum, dbRow* row) {
          return sum + row->getSiteCount();
        });

  logger->info(utl::ODB,
               303,
               "The initial {} rows ({} sites) were cut with {} shapes for a "
               "total of {} rows ({} sites).",
               initial_rows_count,
               initial_sites_count,
               blockages.size(),
               block->getRows().size(),
               final_sites_count);
}

}  // namespace odb
<|endoftext|>