<commit_before>#include "writeback.h"

#include <kernel/kernel.h>

template <typename ISA>
Writeback<ISA>::Writeback( Module* parent, Endian endian) : Module( parent, "writeback"), endian( endian)
{
    rp_mem_datapath = make_read_port<Instr>("MEMORY_2_WRITEBACK", PORT_LATENCY);
    rp_execute_datapath = make_read_port<Instr>("EXECUTE_2_WRITEBACK", PORT_LATENCY);
    rp_branch_datapath = make_read_port<Instr>("BRANCH_2_WRITEBACK", PORT_LATENCY);
    rp_trap = make_read_port<bool>("WRITEBACK_2_ALL_FLUSH", PORT_LATENCY);

    wp_bypass = make_write_port<std::pair<RegisterUInt, RegisterUInt>>("WRITEBACK_2_EXECUTE_BYPASS", PORT_BW);
    wp_halt = make_write_port<Trap>("WRITEBACK_2_CORE_HALT", PORT_BW);
    wp_trap = make_write_port<bool>("WRITEBACK_2_ALL_FLUSH", PORT_BW);
    wp_target = make_write_port<Target>("WRITEBACK_2_FETCH_TARGET", PORT_BW);
}

template<typename ISA>
void Writeback<ISA>::set_target( const Target& value, Cycle cycle)
{
    checker.set_target( value);
    next_PC = value.address;
    wp_trap->write( true, cycle);
    wp_target->write( value, cycle);
}

template <typename ISA>
auto Writeback<ISA>::read_instructions( Cycle cycle)
{
    auto ports = { rp_branch_datapath, rp_mem_datapath, rp_execute_datapath };
    std::vector<Instr> result;

    for ( auto& port : ports)
        if ( port->is_ready( cycle))
            result.emplace_back( port->read( cycle));

    return result;
}

template <typename ISA>
void Writeback<ISA>::clock( Cycle cycle)
{
    sout << "wb      cycle " << std::dec << cycle << ": ";
    if ( rp_trap->is_ready( cycle) && rp_trap->read( cycle)) {
        writeback_bubble( cycle);
        return;
    }

    auto instrs = read_instructions( cycle);

    if ( instrs.empty())
        writeback_bubble( cycle);
    else for ( auto& instr : instrs)
        writeback_instruction_system( &instr, cycle);
}

template <typename ISA>
void Writeback<ISA>::writeback_instruction_system( Writeback<ISA>::Instr* instr, Cycle cycle)
{
    writeback_instruction( *instr, cycle);
    kernel->handle_instruction( instr);
    auto result_trap = driver->handle_trap( *instr);
    checker.driver_step( *instr);
    if ( executed_instrs >= instrs_to_run)
        wp_halt->write( Trap( Trap::BREAKPOINT), cycle);
    else
        wp_halt->write( result_trap, cycle);
    if ( result_trap != Trap::NO_TRAP)
        set_target( instr->get_actual_target(), cycle);
}

template <typename ISA>
void Writeback<ISA>::writeback_bubble( Cycle cycle)
{
    sout << "bubble\n";
    if ( cycle >= last_writeback_cycle + 100_lt)
        throw Deadlock( "");
}

template <typename ISA>
void Writeback<ISA>::writeback_instruction( const Writeback<ISA>::Instr& instr, Cycle cycle)
{
    rf->write_dst( instr);
    wp_bypass->write( std::pair{ instr.get_v_dst(), instr.get_v_dst2()}, cycle);

    sout << instr << std::endl;

    checker.check( instr);
    ++executed_instrs;
    last_writeback_cycle = cycle;
    next_PC = instr.get_actual_target().address;
}

template <typename ISA>
int Writeback<ISA>::get_exit_code() const noexcept
{
    return 0;
}

template <typename ISA>
void Writeback<ISA>::enable_driver_hooks()
{
    driver = Driver::create_hooked_driver( driver.get());
}

#include <mips/mips.h>
#include <risc_v/risc_v.h>

template class Writeback<MIPSI>;
template class Writeback<MIPSII>;
template class Writeback<MIPSIII>;
template class Writeback<MIPSIV>;
template class Writeback<MIPS32>;
template class Writeback<MIPS64>;
template class Writeback<MARS>;
template class Writeback<MARS64>;
template class Writeback<RISCV32>;
template class Writeback<RISCV64>;
template class Writeback<RISCV128>;
<commit_msg>Syscall flushes pipeline<commit_after>#include "writeback.h"

#include <kernel/kernel.h>

template <typename ISA>
Writeback<ISA>::Writeback( Module* parent, Endian endian) : Module( parent, "writeback"), endian( endian)
{
    rp_mem_datapath = make_read_port<Instr>("MEMORY_2_WRITEBACK", PORT_LATENCY);
    rp_execute_datapath = make_read_port<Instr>("EXECUTE_2_WRITEBACK", PORT_LATENCY);
    rp_branch_datapath = make_read_port<Instr>("BRANCH_2_WRITEBACK", PORT_LATENCY);
    rp_trap = make_read_port<bool>("WRITEBACK_2_ALL_FLUSH", PORT_LATENCY);

    wp_bypass = make_write_port<std::pair<RegisterUInt, RegisterUInt>>("WRITEBACK_2_EXECUTE_BYPASS", PORT_BW);
    wp_halt = make_write_port<Trap>("WRITEBACK_2_CORE_HALT", PORT_BW);
    wp_trap = make_write_port<bool>("WRITEBACK_2_ALL_FLUSH", PORT_BW);
    wp_target = make_write_port<Target>("WRITEBACK_2_FETCH_TARGET", PORT_BW);
}

template<typename ISA>
void Writeback<ISA>::set_target( const Target& value, Cycle cycle)
{
    checker.set_target( value);
    next_PC = value.address;
    wp_trap->write( true, cycle);
    wp_target->write( value, cycle);
}

template <typename ISA>
auto Writeback<ISA>::read_instructions( Cycle cycle)
{
    auto ports = { rp_branch_datapath, rp_mem_datapath, rp_execute_datapath };
    std::vector<Instr> result;

    for ( auto& port : ports)
        if ( port->is_ready( cycle))
            result.emplace_back( port->read( cycle));

    return result;
}

template <typename ISA>
void Writeback<ISA>::clock( Cycle cycle)
{
    sout << "wb      cycle " << std::dec << cycle << ": ";
    if ( rp_trap->is_ready( cycle) && rp_trap->read( cycle)) {
        writeback_bubble( cycle);
        return;
    }

    auto instrs = read_instructions( cycle);

    if ( instrs.empty())
        writeback_bubble( cycle);
    else for ( auto& instr : instrs)
        writeback_instruction_system( &instr, cycle);
}

template <typename ISA>
void Writeback<ISA>::writeback_instruction_system( Writeback<ISA>::Instr* instr, Cycle cycle)
{
    writeback_instruction( *instr, cycle);
    auto original_trap = instr->trap_type();
    kernel->handle_instruction( instr);
    auto result_trap = driver->handle_trap( *instr);
    checker.driver_step( *instr);
    if ( executed_instrs >= instrs_to_run)
        wp_halt->write( Trap( Trap::BREAKPOINT), cycle);
    else
        wp_halt->write( result_trap, cycle);
    if ( result_trap != Trap::NO_TRAP || original_trap == Trap::SYSCALL)
        set_target( instr->get_actual_target(), cycle);
}

template <typename ISA>
void Writeback<ISA>::writeback_bubble( Cycle cycle)
{
    sout << "bubble\n";
    if ( cycle >= last_writeback_cycle + 100_lt)
        throw Deadlock( "");
}

template <typename ISA>
void Writeback<ISA>::writeback_instruction( const Writeback<ISA>::Instr& instr, Cycle cycle)
{
    rf->write_dst( instr);
    wp_bypass->write( std::pair{ instr.get_v_dst(), instr.get_v_dst2()}, cycle);

    sout << instr << std::endl;

    checker.check( instr);
    ++executed_instrs;
    last_writeback_cycle = cycle;
    next_PC = instr.get_actual_target().address;
}

template <typename ISA>
int Writeback<ISA>::get_exit_code() const noexcept
{
    return 0;
}

template <typename ISA>
void Writeback<ISA>::enable_driver_hooks()
{
    driver = Driver::create_hooked_driver( driver.get());
}

#include <mips/mips.h>
#include <risc_v/risc_v.h>

template class Writeback<MIPSI>;
template class Writeback<MIPSII>;
template class Writeback<MIPSIII>;
template class Writeback<MIPSIV>;
template class Writeback<MIPS32>;
template class Writeback<MIPS64>;
template class Writeback<MARS>;
template class Writeback<MARS64>;
template class Writeback<RISCV32>;
template class Writeback<RISCV64>;
template class Writeback<RISCV128>;
<|endoftext|>


<commit_before>// Copyright (c) 2012 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/snapshot/snapshot.h"

#include "base/logging.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/aura/window.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/dip_util.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/rect.h"

namespace ui {

bool GrabViewSnapshot(gfx::NativeView view,
                      std::vector<unsigned char>* png_representation,
                      const gfx::Rect& snapshot_bounds) {
  return GrabWindowSnapshot(view, png_representation, snapshot_bounds);
}

bool GrabWindowSnapshot(gfx::NativeWindow window,
                        std::vector<unsigned char>* png_representation,
                        const gfx::Rect& snapshot_bounds) {
  ui::Compositor* compositor = window->layer()->GetCompositor();

  gfx::Rect read_pixels_bounds = snapshot_bounds;

  // When not in compact mode we must take into account the window's position on
  // the desktop.
  read_pixels_bounds.Offset(window->bounds().OffsetFromOrigin());
  gfx::Rect read_pixels_bounds_in_pixel =
      ui::ConvertRectToPixel(window->layer(), read_pixels_bounds);

  // Sometimes (i.e. when using Aero on Windows) the compositor's size is
  // smaller than the window bounds. So trim appropriately.
  read_pixels_bounds_in_pixel.Intersect(gfx::Rect(compositor->size()));

  DCHECK_LE(0, read_pixels_bounds.x());
  DCHECK_LE(0, read_pixels_bounds.y());

  SkBitmap bitmap;
  if (!compositor->ReadPixels(&bitmap, read_pixels_bounds_in_pixel))
    return false;

  unsigned char* pixels = reinterpret_cast<unsigned char*>(bitmap.getPixels());

  gfx::PNGCodec::Encode(pixels, gfx::PNGCodec::FORMAT_BGRA,
                        read_pixels_bounds_in_pixel.size(),
                        bitmap.rowBytes(), true,
                        std::vector<gfx::PNGCodec::Comment>(),
                        png_representation);
  return true;
}

}  // namespace ui
<commit_msg>Fix GrabWindowSnapshot not taking into account parents when calculating window offset.<commit_after>// Copyright (c) 2012 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/snapshot/snapshot.h"

#include "base/logging.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/dip_util.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/rect.h"

namespace ui {

bool GrabViewSnapshot(gfx::NativeView view,
                      std::vector<unsigned char>* png_representation,
                      const gfx::Rect& snapshot_bounds) {
  return GrabWindowSnapshot(view, png_representation, snapshot_bounds);
}

bool GrabWindowSnapshot(gfx::NativeWindow window,
                        std::vector<unsigned char>* png_representation,
                        const gfx::Rect& snapshot_bounds) {
  ui::Compositor* compositor = window->layer()->GetCompositor();

  gfx::Rect read_pixels_bounds = snapshot_bounds;

  // We must take into account the window's position on the desktop.
  gfx::Point origin = window->bounds().origin();
  const aura::Window* root_window = window->GetRootWindow();
  if (root_window)
    aura::Window::ConvertPointToTarget(window, root_window, &origin);

  read_pixels_bounds.Offset(origin.OffsetFromOrigin());
  gfx::Rect read_pixels_bounds_in_pixel =
      ui::ConvertRectToPixel(window->layer(), read_pixels_bounds);

  // Sometimes (i.e. when using Aero on Windows) the compositor's size is
  // smaller than the window bounds. So trim appropriately.
  read_pixels_bounds_in_pixel.Intersect(gfx::Rect(compositor->size()));

  DCHECK_LE(0, read_pixels_bounds.x());
  DCHECK_LE(0, read_pixels_bounds.y());

  SkBitmap bitmap;
  if (!compositor->ReadPixels(&bitmap, read_pixels_bounds_in_pixel))
    return false;

  unsigned char* pixels = reinterpret_cast<unsigned char*>(bitmap.getPixels());

  gfx::PNGCodec::Encode(pixels, gfx::PNGCodec::FORMAT_BGRA,
                        read_pixels_bounds_in_pixel.size(),
                        bitmap.rowBytes(), true,
                        std::vector<gfx::PNGCodec::Comment>(),
                        png_representation);
  return true;
}

}  // namespace ui
<|endoftext|>


<commit_before>//===----------- Triple.cpp - Triple unit tests ---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "gtest/gtest.h"
#include "llvm/ADT/Triple.h"

using namespace llvm;

namespace {

TEST(TripleTest, BasicParsing) {
  Triple T;

  T = Triple("");
  EXPECT_EQ("", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("-");
  EXPECT_EQ("", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("--");
  EXPECT_EQ("", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("---");
  EXPECT_EQ("", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("----");
  EXPECT_EQ("", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("-", T.getEnvironmentName().str());

  T = Triple("a");
  EXPECT_EQ("a", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("a-b");
  EXPECT_EQ("a", T.getArchName().str());
  EXPECT_EQ("b", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("a-b-c");
  EXPECT_EQ("a", T.getArchName().str());
  EXPECT_EQ("b", T.getVendorName().str());
  EXPECT_EQ("c", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("a-b-c-d");
  EXPECT_EQ("a", T.getArchName().str());
  EXPECT_EQ("b", T.getVendorName().str());
  EXPECT_EQ("c", T.getOSName().str());
  EXPECT_EQ("d", T.getEnvironmentName().str());
}

TEST(TripleTest, ParsedIDs) {
  Triple T;

  T = Triple("i386-apple-darwin");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::Apple, T.getVendor());
  EXPECT_EQ(Triple::Darwin, T.getOS());
  EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());

  T = Triple("x86_64-pc-linux-gnu");
  EXPECT_EQ(Triple::x86_64, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ(Triple::Linux, T.getOS());
  EXPECT_EQ(Triple::GNU, T.getEnvironment());

  T = Triple("powerpc-dunno-notsure");
  EXPECT_EQ(Triple::ppc, T.getArch());
  EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
  EXPECT_EQ(Triple::UnknownOS, T.getOS());
  EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());

  T = Triple("arm-none-none-eabi");
  EXPECT_EQ(Triple::arm, T.getArch());
  EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
  EXPECT_EQ(Triple::UnknownOS, T.getOS());
  EXPECT_EQ(Triple::EABI, T.getEnvironment());

  T = Triple("huh");
  EXPECT_EQ(Triple::UnknownArch, T.getArch());
}

static std::string Join(StringRef A, StringRef B, StringRef C) {
  std::string Str = A; Str += '-'; Str += B; Str += '-'; Str += C;
  return Str;
}

static std::string Join(StringRef A, StringRef B, StringRef C, StringRef D) {
  std::string Str = A; Str += '-'; Str += B; Str += '-'; Str += C; Str += '-';
  Str += D; return Str;
}

TEST(TripleTest, Normalization) {

  EXPECT_EQ("", Triple::normalize(""));
  EXPECT_EQ("-", Triple::normalize("-"));
  EXPECT_EQ("--", Triple::normalize("--"));
  EXPECT_EQ("---", Triple::normalize("---"));
  EXPECT_EQ("----", Triple::normalize("----"));

  EXPECT_EQ("a", Triple::normalize("a"));
  EXPECT_EQ("a-b", Triple::normalize("a-b"));
  EXPECT_EQ("a-b-c", Triple::normalize("a-b-c"));
  EXPECT_EQ("a-b-c-d", Triple::normalize("a-b-c-d"));

  EXPECT_EQ("i386-b-c", Triple::normalize("i386-b-c"));
  EXPECT_EQ("i386-a-c", Triple::normalize("a-i386-c"));
  EXPECT_EQ("i386-a-b", Triple::normalize("a-b-i386"));
  EXPECT_EQ("i386-a-b-c", Triple::normalize("a-b-c-i386"));

  EXPECT_EQ("a-pc-c", Triple::normalize("a-pc-c"));
  EXPECT_EQ("-pc-b-c", Triple::normalize("pc-b-c"));
  EXPECT_EQ("a-pc-b", Triple::normalize("a-b-pc"));
  EXPECT_EQ("a-pc-b-c", Triple::normalize("a-b-c-pc"));

  EXPECT_EQ("a-b-linux", Triple::normalize("a-b-linux"));
  EXPECT_EQ("--linux-b-c", Triple::normalize("linux-b-c"));
  EXPECT_EQ("a--linux-c", Triple::normalize("a-linux-c"));

  EXPECT_EQ("i386-pc-a", Triple::normalize("a-pc-i386"));
  EXPECT_EQ("i386-pc-", Triple::normalize("-pc-i386"));
  EXPECT_EQ("-pc-linux-c", Triple::normalize("linux-pc-c"));
  EXPECT_EQ("-pc-linux", Triple::normalize("linux-pc-"));

  EXPECT_EQ("i386", Triple::normalize("i386"));
  EXPECT_EQ("-pc", Triple::normalize("pc"));
  EXPECT_EQ("--linux", Triple::normalize("linux"));

  EXPECT_EQ("x86_64--linux-gnu", Triple::normalize("x86_64-gnu-linux"));

  // Check that normalizing a permutated set of valid components returns a
  // triple with the unpermuted components.
  StringRef C[4];
  for (int Arch = 1+Triple::UnknownArch; Arch < Triple::InvalidArch; ++Arch) {
    C[0] = Triple::getArchTypeName(Triple::ArchType(Arch));
    for (int Vendor = 1+Triple::UnknownVendor; Vendor <= Triple::PC;
         ++Vendor) {
      C[1] = Triple::getVendorTypeName(Triple::VendorType(Vendor));
      for (int OS = 1+Triple::UnknownOS; OS <= Triple::Minix; ++OS) {
        C[2] = Triple::getOSTypeName(Triple::OSType(OS));
        for (int Env = 1+Triple::UnknownEnvironment; Env <= Triple::MachO;
             ++Env) {
          C[3] = Triple::getEnvironmentTypeName(Triple::EnvironmentType(Env));

          std::string E = Join(C[0], C[1], C[2]);
          std::string F = Join(C[0], C[1], C[2], C[3]);
          EXPECT_EQ(E, Triple::normalize(Join(C[0], C[1], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[1], C[2], C[3])));

          // If a value has multiple interpretations, then the permutation
          // test will inevitably fail.  Currently this is only the case for
          // "psp" which parses as both an architecture and an O/S.
          if (OS == Triple::Psp)
            continue;

          EXPECT_EQ(E, Triple::normalize(Join(C[0], C[2], C[1])));
          EXPECT_EQ(E, Triple::normalize(Join(C[1], C[2], C[0])));
          EXPECT_EQ(E, Triple::normalize(Join(C[1], C[0], C[2])));
          EXPECT_EQ(E, Triple::normalize(Join(C[2], C[0], C[1])));
          EXPECT_EQ(E, Triple::normalize(Join(C[2], C[1], C[0])));

          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[1], C[3], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[2], C[3], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[2], C[1], C[3])));
          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[3], C[1], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[3], C[2], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[2], C[3], C[0])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[2], C[0], C[3])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[3], C[0], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[3], C[2], C[0])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[0], C[2], C[3])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[0], C[3], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[3], C[0], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[3], C[1], C[0])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[0], C[1], C[3])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[0], C[3], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[1], C[3], C[0])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[1], C[0], C[3])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[0], C[1], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[0], C[2], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[1], C[2], C[0])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[1], C[0], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[2], C[0], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[2], C[1], C[0])));
        }
      }
    }
  }

  EXPECT_EQ("a-b-psp", Triple::normalize("a-b-psp"));
  EXPECT_EQ("psp-b-c", Triple::normalize("psp-b-c"));

  // Various real-world funky triples.  The value returned by GCC's config.sub
  // is given in the comment.
  EXPECT_EQ("i386--mingw32", Triple::normalize("i386-mingw32")); // i386-pc-mingw32
  EXPECT_EQ("x86_64--linux-gnu", Triple::normalize("x86_64-linux-gnu")); // x86_64-pc-linux-gnu
  EXPECT_EQ("i486--linux-gnu", Triple::normalize("i486-linux-gnu")); // i486-pc-linux-gnu
  EXPECT_EQ("i386-redhat-linux", Triple::normalize("i386-redhat-linux")); // i386-redhat-linux-gnu
  EXPECT_EQ("i686--linux", Triple::normalize("i686-linux")); // i686-pc-linux-gnu
  EXPECT_EQ("arm-none--eabi", Triple::normalize("arm-none-eabi")); // arm-none-eabi
}

TEST(TripleTest, MutateName) {
  Triple T;
  EXPECT_EQ(Triple::UnknownArch, T.getArch());
  EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
  EXPECT_EQ(Triple::UnknownOS, T.getOS());
  EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());

  T.setArchName("i386");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ("i386--", T.getTriple());

  T.setVendorName("pc");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ("i386-pc-", T.getTriple());

  T.setOSName("linux");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ(Triple::Linux, T.getOS());
  EXPECT_EQ("i386-pc-linux", T.getTriple());

  T.setEnvironmentName("gnu");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ(Triple::Linux, T.getOS());
  EXPECT_EQ("i386-pc-linux-gnu", T.getTriple());

  T.setOSName("freebsd");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ(Triple::FreeBSD, T.getOS());
  EXPECT_EQ("i386-pc-freebsd-gnu", T.getTriple());

  T.setOSAndEnvironmentName("darwin");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ(Triple::Darwin, T.getOS());
  EXPECT_EQ("i386-pc-darwin", T.getTriple());

}

}
<commit_msg>Part of this test is invariant inside the inner loop - move it outside the loop.<commit_after>//===----------- Triple.cpp - Triple unit tests ---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "gtest/gtest.h"
#include "llvm/ADT/Triple.h"

using namespace llvm;

namespace {

TEST(TripleTest, BasicParsing) {
  Triple T;

  T = Triple("");
  EXPECT_EQ("", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("-");
  EXPECT_EQ("", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("--");
  EXPECT_EQ("", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("---");
  EXPECT_EQ("", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("----");
  EXPECT_EQ("", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("-", T.getEnvironmentName().str());

  T = Triple("a");
  EXPECT_EQ("a", T.getArchName().str());
  EXPECT_EQ("", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("a-b");
  EXPECT_EQ("a", T.getArchName().str());
  EXPECT_EQ("b", T.getVendorName().str());
  EXPECT_EQ("", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("a-b-c");
  EXPECT_EQ("a", T.getArchName().str());
  EXPECT_EQ("b", T.getVendorName().str());
  EXPECT_EQ("c", T.getOSName().str());
  EXPECT_EQ("", T.getEnvironmentName().str());

  T = Triple("a-b-c-d");
  EXPECT_EQ("a", T.getArchName().str());
  EXPECT_EQ("b", T.getVendorName().str());
  EXPECT_EQ("c", T.getOSName().str());
  EXPECT_EQ("d", T.getEnvironmentName().str());
}

TEST(TripleTest, ParsedIDs) {
  Triple T;

  T = Triple("i386-apple-darwin");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::Apple, T.getVendor());
  EXPECT_EQ(Triple::Darwin, T.getOS());
  EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());

  T = Triple("x86_64-pc-linux-gnu");
  EXPECT_EQ(Triple::x86_64, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ(Triple::Linux, T.getOS());
  EXPECT_EQ(Triple::GNU, T.getEnvironment());

  T = Triple("powerpc-dunno-notsure");
  EXPECT_EQ(Triple::ppc, T.getArch());
  EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
  EXPECT_EQ(Triple::UnknownOS, T.getOS());
  EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());

  T = Triple("arm-none-none-eabi");
  EXPECT_EQ(Triple::arm, T.getArch());
  EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
  EXPECT_EQ(Triple::UnknownOS, T.getOS());
  EXPECT_EQ(Triple::EABI, T.getEnvironment());

  T = Triple("huh");
  EXPECT_EQ(Triple::UnknownArch, T.getArch());
}

static std::string Join(StringRef A, StringRef B, StringRef C) {
  std::string Str = A; Str += '-'; Str += B; Str += '-'; Str += C;
  return Str;
}

static std::string Join(StringRef A, StringRef B, StringRef C, StringRef D) {
  std::string Str = A; Str += '-'; Str += B; Str += '-'; Str += C; Str += '-';
  Str += D; return Str;
}

TEST(TripleTest, Normalization) {

  EXPECT_EQ("", Triple::normalize(""));
  EXPECT_EQ("-", Triple::normalize("-"));
  EXPECT_EQ("--", Triple::normalize("--"));
  EXPECT_EQ("---", Triple::normalize("---"));
  EXPECT_EQ("----", Triple::normalize("----"));

  EXPECT_EQ("a", Triple::normalize("a"));
  EXPECT_EQ("a-b", Triple::normalize("a-b"));
  EXPECT_EQ("a-b-c", Triple::normalize("a-b-c"));
  EXPECT_EQ("a-b-c-d", Triple::normalize("a-b-c-d"));

  EXPECT_EQ("i386-b-c", Triple::normalize("i386-b-c"));
  EXPECT_EQ("i386-a-c", Triple::normalize("a-i386-c"));
  EXPECT_EQ("i386-a-b", Triple::normalize("a-b-i386"));
  EXPECT_EQ("i386-a-b-c", Triple::normalize("a-b-c-i386"));

  EXPECT_EQ("a-pc-c", Triple::normalize("a-pc-c"));
  EXPECT_EQ("-pc-b-c", Triple::normalize("pc-b-c"));
  EXPECT_EQ("a-pc-b", Triple::normalize("a-b-pc"));
  EXPECT_EQ("a-pc-b-c", Triple::normalize("a-b-c-pc"));

  EXPECT_EQ("a-b-linux", Triple::normalize("a-b-linux"));
  EXPECT_EQ("--linux-b-c", Triple::normalize("linux-b-c"));
  EXPECT_EQ("a--linux-c", Triple::normalize("a-linux-c"));

  EXPECT_EQ("i386-pc-a", Triple::normalize("a-pc-i386"));
  EXPECT_EQ("i386-pc-", Triple::normalize("-pc-i386"));
  EXPECT_EQ("-pc-linux-c", Triple::normalize("linux-pc-c"));
  EXPECT_EQ("-pc-linux", Triple::normalize("linux-pc-"));

  EXPECT_EQ("i386", Triple::normalize("i386"));
  EXPECT_EQ("-pc", Triple::normalize("pc"));
  EXPECT_EQ("--linux", Triple::normalize("linux"));

  EXPECT_EQ("x86_64--linux-gnu", Triple::normalize("x86_64-gnu-linux"));

  // Check that normalizing a permutated set of valid components returns a
  // triple with the unpermuted components.
  StringRef C[4];
  for (int Arch = 1+Triple::UnknownArch; Arch < Triple::InvalidArch; ++Arch) {
    C[0] = Triple::getArchTypeName(Triple::ArchType(Arch));
    for (int Vendor = 1+Triple::UnknownVendor; Vendor <= Triple::PC;
         ++Vendor) {
      C[1] = Triple::getVendorTypeName(Triple::VendorType(Vendor));
      for (int OS = 1+Triple::UnknownOS; OS <= Triple::Minix; ++OS) {
        C[2] = Triple::getOSTypeName(Triple::OSType(OS));

        // If a value has multiple interpretations, then the permutation
        // test will inevitably fail.  Currently this is only the case for
        // "psp" which parses as both an architecture and an O/S.
        if (OS == Triple::Psp)
          continue;

        std::string E = Join(C[0], C[1], C[2]);
        EXPECT_EQ(E, Triple::normalize(Join(C[0], C[1], C[2])));

        EXPECT_EQ(E, Triple::normalize(Join(C[0], C[2], C[1])));
        EXPECT_EQ(E, Triple::normalize(Join(C[1], C[2], C[0])));
        EXPECT_EQ(E, Triple::normalize(Join(C[1], C[0], C[2])));
        EXPECT_EQ(E, Triple::normalize(Join(C[2], C[0], C[1])));
        EXPECT_EQ(E, Triple::normalize(Join(C[2], C[1], C[0])));

        for (int Env = 1+Triple::UnknownEnvironment; Env <= Triple::MachO;
             ++Env) {
          C[3] = Triple::getEnvironmentTypeName(Triple::EnvironmentType(Env));

          std::string F = Join(C[0], C[1], C[2], C[3]);
          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[1], C[2], C[3])));

          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[1], C[3], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[2], C[3], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[2], C[1], C[3])));
          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[3], C[1], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[0], C[3], C[2], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[2], C[3], C[0])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[2], C[0], C[3])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[3], C[0], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[3], C[2], C[0])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[0], C[2], C[3])));
          EXPECT_EQ(F, Triple::normalize(Join(C[1], C[0], C[3], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[3], C[0], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[3], C[1], C[0])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[0], C[1], C[3])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[0], C[3], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[1], C[3], C[0])));
          EXPECT_EQ(F, Triple::normalize(Join(C[2], C[1], C[0], C[3])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[0], C[1], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[0], C[2], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[1], C[2], C[0])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[1], C[0], C[2])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[2], C[0], C[1])));
          EXPECT_EQ(F, Triple::normalize(Join(C[3], C[2], C[1], C[0])));
        }
      }
    }
  }

  EXPECT_EQ("a-b-psp", Triple::normalize("a-b-psp"));
  EXPECT_EQ("psp-b-c", Triple::normalize("psp-b-c"));

  // Various real-world funky triples.  The value returned by GCC's config.sub
  // is given in the comment.
  EXPECT_EQ("i386--mingw32", Triple::normalize("i386-mingw32")); // i386-pc-mingw32
  EXPECT_EQ("x86_64--linux-gnu", Triple::normalize("x86_64-linux-gnu")); // x86_64-pc-linux-gnu
  EXPECT_EQ("i486--linux-gnu", Triple::normalize("i486-linux-gnu")); // i486-pc-linux-gnu
  EXPECT_EQ("i386-redhat-linux", Triple::normalize("i386-redhat-linux")); // i386-redhat-linux-gnu
  EXPECT_EQ("i686--linux", Triple::normalize("i686-linux")); // i686-pc-linux-gnu
  EXPECT_EQ("arm-none--eabi", Triple::normalize("arm-none-eabi")); // arm-none-eabi
}

TEST(TripleTest, MutateName) {
  Triple T;
  EXPECT_EQ(Triple::UnknownArch, T.getArch());
  EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
  EXPECT_EQ(Triple::UnknownOS, T.getOS());
  EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());

  T.setArchName("i386");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ("i386--", T.getTriple());

  T.setVendorName("pc");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ("i386-pc-", T.getTriple());

  T.setOSName("linux");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ(Triple::Linux, T.getOS());
  EXPECT_EQ("i386-pc-linux", T.getTriple());

  T.setEnvironmentName("gnu");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ(Triple::Linux, T.getOS());
  EXPECT_EQ("i386-pc-linux-gnu", T.getTriple());

  T.setOSName("freebsd");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ(Triple::FreeBSD, T.getOS());
  EXPECT_EQ("i386-pc-freebsd-gnu", T.getTriple());

  T.setOSAndEnvironmentName("darwin");
  EXPECT_EQ(Triple::x86, T.getArch());
  EXPECT_EQ(Triple::PC, T.getVendor());
  EXPECT_EQ(Triple::Darwin, T.getOS());
  EXPECT_EQ("i386-pc-darwin", T.getTriple());

}

}
<|endoftext|>


<commit_before>#include "Mark.hpp"

#include <Constants.hpp>

#include <iostream>

using namespace std;
using namespace Geometry2d;

Gameplay::Behaviors::Mark::Mark(GameplayModule *gameplay):
SingleRobotBehavior(gameplay),
_ratio(0.9),
_mark_line_thresh(0.9)
{
}

void Gameplay::Behaviors::Mark::ratio(float r)
{
	if (r > 1.0) {
		_ratio = 1.0;
	} else if (r < 0.0) {
		_ratio = 0.0;
	} else {
		_ratio = r;
	}
}

bool Gameplay::Behaviors::Mark::run()
{
	if (!robot || !robot->visible)
	{
		return false;
	}
	if (!ball().valid)
	{
		return false;
	}
	if (_markRobot && _markRobot->visible) {
		// state data
		Point ballPos = ball().pos,
			  ballVel = ball().vel,
			  pos = robot->pos,
			  markPos = _markRobot->pos,
			  markVel = _markRobot->vel;
		Point markLineDir = (ballPos-markPos).normalized();
		Segment ballMarkLine(ballPos - markLineDir * Ball_Radius,
				markPos + markLineDir * 2.0 * Robot_Radius);

		state()->drawLine(ballMarkLine, QColor(0, 0, 255, 255), "Mark");
		robot->addText("Mark", QColor(255, 255, 255, 255));

		// we want to get between the mark and the ball as fast as possible, then close in
		float markLineDist = ballMarkLine.distTo(pos);
		Point targetPoint;
		if (markLineDist > _mark_line_thresh) {
			// fast intercept possible passes
			targetPoint = ballMarkLine.nearestPoint(pos);
		} else {
			// drive to the given point specified by ratio
			targetPoint = ballPos + (markPos - ballPos).normalized()* _ratio * ballMarkLine.length();
		}

		state()->drawCircle(_markRobot->pos, Robot_Radius * 1.2, QColor(0.0, 127, 255, 255), "Mark");

		// go there, facing the ball
		robot->approachOpp(_markRobot, true);
		robot->move(targetPoint, false);
		robot->face(ballPos);

	} else {
		return false;
	}

	return true;
}
<commit_msg>fixed bad pointer<commit_after>#include "Mark.hpp"

#include <Constants.hpp>

#include <iostream>

using namespace std;
using namespace Geometry2d;

Gameplay::Behaviors::Mark::Mark(GameplayModule *gameplay):
SingleRobotBehavior(gameplay),
_markRobot(NULL),
_ratio(0.9),
_mark_line_thresh(0.9)
{
}

void Gameplay::Behaviors::Mark::ratio(float r)
{
	if (r > 1.0) {
		_ratio = 1.0;
	} else if (r < 0.0) {
		_ratio = 0.0;
	} else {
		_ratio = r;
	}
}

bool Gameplay::Behaviors::Mark::run()
{
	if (!robot || !robot->visible)
	{
		return false;
	}
	if (!ball().valid)
	{
		return false;
	}
	if (_markRobot && _markRobot->visible) {
		// state data
		Point ballPos = ball().pos,
			  ballVel = ball().vel,
			  pos = robot->pos,
			  markPos = _markRobot->pos,
			  markVel = _markRobot->vel;
		Point markLineDir = (ballPos-markPos).normalized();
		Segment ballMarkLine(ballPos - markLineDir * Ball_Radius,
				markPos + markLineDir * 2.0 * Robot_Radius);

		state()->drawLine(ballMarkLine, QColor(0, 0, 255, 255), "Mark");
		robot->addText("Mark", QColor(255, 255, 255, 255));

		// we want to get between the mark and the ball as fast as possible, then close in
		float markLineDist = ballMarkLine.distTo(pos);
		Point targetPoint;
		if (markLineDist > _mark_line_thresh) {
			// fast intercept possible passes
			targetPoint = ballMarkLine.nearestPoint(pos);
		} else {
			// drive to the given point specified by ratio
			targetPoint = ballPos + (markPos - ballPos).normalized()* _ratio * ballMarkLine.length();
		}

		state()->drawCircle(_markRobot->pos, Robot_Radius * 1.2, QColor(0.0, 127, 255, 255), "Mark");

		// go there, facing the ball
		robot->approachOpp(_markRobot, true);
		robot->move(targetPoint, false);
		robot->face(ballPos);

	} else {
		return false;
	}

	return true;
}
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <unistd.h>
#include <cstdio>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <fstream>

#include "minizinc/solvers/fzn_solverinstance.hh"

#include <minizinc/parser.hh>
#include <minizinc/prettyprinter.hh>
#include <minizinc/typecheck.hh>
#include <minizinc/builtins.hh>
#include <minizinc/eval_par.hh>

namespace MiniZinc {

  namespace {
    class FznProcess {
    protected:
      std::string _fzncmd;
      bool _canPipe;
      Model* _flat;
    public:
      FznProcess(const std::string& fzncmd, bool pipe, Model* flat) : _fzncmd(fzncmd), _canPipe(pipe), _flat(flat) {}
      std::string run(void) {
        int pipes[2][2];
        pipe(pipes[0]);
        pipe(pipes[1]);

        std::string fznFile;
        if (!_canPipe) {
          char tmpfile[] = "/tmp/fznfileXXXXXX";
          mkstemp(tmpfile);
          fznFile = tmpfile;
          std::ofstream os(tmpfile);
          for (Model::iterator it = _flat->begin(); it != _flat->end(); ++it) {
            Item* item = *it;
            os << *item;
          }
        }

        if (int childPID = fork()) {
          close(pipes[0][0]);
          close(pipes[1][1]);
          if (_canPipe) {
            for (Model::iterator it = _flat->begin(); it != _flat->end(); ++it) {
              std::stringstream ss;
              Item* item = *it;
              ss << *item;
              std::string str = ss.str();
              write(pipes[0][1], str.c_str(), str.size());
            }
          }
          close(pipes[0][1]);
          std::stringstream result;

          fd_set fdset;
          struct timeval timeout;
          FD_ZERO(&fdset);
          FD_SET(pipes[1][0], &fdset);

          struct timeval starttime;
          gettimeofday(&starttime, NULL);

          int timeout_sec = 10;

          timeout.tv_sec = timeout_sec;
          timeout.tv_usec = 0;

          bool done = false;
          while (!done) {
            switch (select(FD_SETSIZE, &fdset, NULL, NULL, &timeout)) {
              case 0:
              {
                kill(childPID, SIGKILL);
                done = true;
              }
                break;
              case 1:
              {
                char buffer[100];
                int count = read(pipes[1][0], buffer, sizeof(buffer)-1);
                if (count > 0) {
                  buffer[count] = 0;
                  result << buffer;
                  timeval currentTime, elapsed;
                  gettimeofday(&currentTime, NULL);
                  elapsed.tv_sec = currentTime.tv_sec - starttime.tv_sec;
                  elapsed.tv_usec = currentTime.tv_usec - starttime.tv_usec;
                  if (elapsed.tv_usec < 0) {
                    elapsed.tv_sec--;
                    elapsed.tv_usec += 1000000;
                  }
                  timeout.tv_sec = timeout_sec - elapsed.tv_sec;
                  if (elapsed.tv_usec > 0)
                    timeout.tv_sec--;
                  timeout.tv_usec = 1000000 - elapsed.tv_usec;
                  if (timeout.tv_sec <= 0 && timeout.tv_usec <=0)
                    done = true;
                } else {
                  done = true;
                }
              }
                break;
              case -1:
              {
              }
                break;
            }
          }

          if (!_canPipe) {
            remove(fznFile.c_str());
          }
          return result.str();
        } else {
          close(STDOUT_FILENO);
          close(STDIN_FILENO);
          dup2(pipes[0][0], STDIN_FILENO);
          dup2(pipes[1][1], STDOUT_FILENO);
          close(pipes[0][0]);
          close(pipes[1][1]);
          close(pipes[1][0]);
          close(pipes[0][1]);
          char* argv[] = {strdup(_fzncmd.c_str()),strdup("-a"),strdup("-"),0};
          if (!_canPipe) {
            argv[2] = strdup(fznFile.c_str());
          }
          execvp(argv[0],argv);
        }
        assert(false);
      }
    };
  }

  FZNSolverInstance::FZNSolverInstance(Env& env, const Options& options)
  : SolverInstanceImpl<FZNSolver>(env,options), _fzn(env.flat()), _ozn(env.output()) {}

  FZNSolverInstance::~FZNSolverInstance(void) {}

  SolverInstance::Status
  FZNSolverInstance::next(void) { return SolverInstance::ERROR; }

  namespace {
    ArrayLit* b_arrayXd(Env& env, ASTExprVec<Expression> args, int d) {
      GCLock lock;
      ArrayLit* al = eval_array_lit(env.envi(), args[d]);
      std::vector<std::pair<int,int> > dims(d);
      unsigned int dim1d = 1;
      for (int i=0; i<d; i++) {
        IntSetVal* di = eval_intset(env.envi(), args[i]);
        if (di->size()==0) {
          dims[i] = std::pair<int,int>(1,0);
          dim1d = 0;
        } else if (di->size() != 1) {
          throw EvalError(env.envi(), args[i]->loc(), "arrayXd only defined for ranges");
        } else {
          dims[i] = std::pair<int,int>(static_cast<int>(di->min(0).toInt()),
                                       static_cast<int>(di->max(0).toInt()));
          dim1d *= dims[i].second-dims[i].first+1;
        }
      }
      if (dim1d != al->v().size())
        throw EvalError(env.envi(), al->loc(), "mismatch in array dimensions");
      ArrayLit* ret = new ArrayLit(al->loc(), al->v(), dims);
      Type t = al->type();
      t.dim(d);
      ret->type(t);
      ret->flat(al->flat());
      return ret;
    }
  }

  SolverInstance::Status
  FZNSolverInstance::solve(void) {
    std::vector<std::string> includePaths;
    FznProcess proc("fzn-gecode",false,_fzn);
    std::string r = proc.run();
    std::stringstream result;
    result << r;
    std::string solution;

    typedef std::pair<VarDecl*,Expression*> DE;
    ASTStringMap<DE>::t declmap;
    for (unsigned int i=0; i<_ozn->size(); i++) {
      if (VarDeclI* vdi = (*_ozn)[i]->dyn_cast<VarDeclI>()) {
        declmap.insert(std::make_pair(vdi->e()->id()->v(),DE(vdi->e(),vdi->e()->e())));
      }
    }

    bool hadSolution = false;
    while (result.good()) {
      std::string line;
      getline(result, line);
      if (line=="----------") {
        if (hadSolution) {
          for (ASTStringMap<DE>::t::iterator it=declmap.begin(); it != declmap.end(); ++it) {
            it->second.first->e(it->second.second);
          }
        }
        Model* sm = parseFromString(solution, "solution.szn", includePaths, true, false, false, std::cerr);
        for (Model::iterator it = sm->begin(); it != sm->end(); ++it) {
          if (AssignI* ai = (*it)->dyn_cast<AssignI>()) {
            ASTStringMap<DE>::t::iterator it = declmap.find(ai->id());
            if (it==declmap.end()) {
              std::cerr << "Error: unexpected identifier " << ai->id() << " in output\n";
              exit(EXIT_FAILURE);
            }
            if (Call* c = ai->e()->dyn_cast<Call>()) {
              // This is an arrayXd call, make sure we get the right builtin
              assert(c->args()[c->args().size()-1]->isa<ArrayLit>());
              for (unsigned int i=0; i<c->args().size(); i++)
                c->args()[i]->type(Type::parsetint());
              c->args()[c->args().size()-1]->type(it->second.first->type());
              ArrayLit* al = b_arrayXd(_env, c->args(), c->args().size()-1);
              it->second.first->e(al);
            } else {
              it->second.first->e(ai->e());
            }
          }
        }
        delete sm;
        hadSolution = true;
      } else if (line=="==========") {
        return hadSolution ? SolverInstance::OPT : SolverInstance::UNSAT;
      } else if(line=="=====UNSATISFIABLE=====") {
        return SolverInstance::UNSAT;
      } else if(line=="=====UNBOUNDED=====") {
        return SolverInstance::UNKNOWN;
      } else if(line=="=====UNKNOWN=====") {
        return SolverInstance::UNKNOWN;
      } else {
        solution += line;
      }
    }

    return hadSolution ? SolverInstance::SAT : SolverInstance::UNSAT;
  }

  void
  FZNSolverInstance::processFlatZinc(void) {}

  void
  FZNSolverInstance::resetSolver(void) {}

  Expression*
  FZNSolverInstance::getSolutionValue(Id* id) {
    assert(false);
  }

}
<commit_msg>extended fzn-solverinterface to consider solver given by CL and throwing exception when error occurs when executing the FZN solver<commit_after>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <unistd.h>
#include <cstdio>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <fstream>

#include "minizinc/solvers/fzn_solverinstance.hh"

#include <minizinc/parser.hh>
#include <minizinc/prettyprinter.hh>
#include <minizinc/typecheck.hh>
#include <minizinc/builtins.hh>
#include <minizinc/eval_par.hh>

namespace MiniZinc {

  namespace {
    class FznProcess {
    protected:
      std::string _fzncmd;
      bool _canPipe;
      Model* _flat;
    public:
      FznProcess(const std::string& fzncmd, bool pipe, Model* flat) : _fzncmd(fzncmd), _canPipe(pipe), _flat(flat) {}
      std::string run(void) {
        int pipes[2][2];
        pipe(pipes[0]);
        pipe(pipes[1]);

        std::string fznFile;
        if (!_canPipe) {
          char tmpfile[] = "/tmp/fznfileXXXXXX";
          mkstemp(tmpfile);
          fznFile = tmpfile;
          std::ofstream os(tmpfile);
          for (Model::iterator it = _flat->begin(); it != _flat->end(); ++it) {
            Item* item = *it;
            os << *item;
          }
        }

        if (int childPID = fork()) {
          close(pipes[0][0]);
          close(pipes[1][1]);
          if (_canPipe) {
            for (Model::iterator it = _flat->begin(); it != _flat->end(); ++it) {
              std::stringstream ss;
              Item* item = *it;
              ss << *item;
              std::string str = ss.str();
              write(pipes[0][1], str.c_str(), str.size());
            }
          }
          close(pipes[0][1]);
          std::stringstream result;

          fd_set fdset;
          struct timeval timeout;
          FD_ZERO(&fdset);
          FD_SET(pipes[1][0], &fdset);

          struct timeval starttime;
          gettimeofday(&starttime, NULL);

          int timeout_sec = 10;

          timeout.tv_sec = timeout_sec;
          timeout.tv_usec = 0;

          bool done = false;
          while (!done) {
            switch (select(FD_SETSIZE, &fdset, NULL, NULL, &timeout)) {
              case 0:
              {
                kill(childPID, SIGKILL);
                done = true;
              }
                break;
              case 1:
              {
                char buffer[100];
                int count = read(pipes[1][0], buffer, sizeof(buffer)-1);
                if (count > 0) {
                  buffer[count] = 0;
                  result << buffer;
                  timeval currentTime, elapsed;
                  gettimeofday(&currentTime, NULL);
                  elapsed.tv_sec = currentTime.tv_sec - starttime.tv_sec;
                  elapsed.tv_usec = currentTime.tv_usec - starttime.tv_usec;
                  if (elapsed.tv_usec < 0) {
                    elapsed.tv_sec--;
                    elapsed.tv_usec += 1000000;
                  }
                  timeout.tv_sec = timeout_sec - elapsed.tv_sec;
                  if (elapsed.tv_usec > 0)
                    timeout.tv_sec--;
                  timeout.tv_usec = 1000000 - elapsed.tv_usec;
                  if (timeout.tv_sec <= 0 && timeout.tv_usec <=0)
                    done = true;
                } else {
                  done = true;
                }
              }
                break;
              case -1:
              {
              }
                break;
            }
          }

          if (!_canPipe) {
            remove(fznFile.c_str());
          }
          return result.str();
        } else {
          close(STDOUT_FILENO);
          close(STDIN_FILENO);
          dup2(pipes[0][0], STDIN_FILENO);
          dup2(pipes[1][1], STDOUT_FILENO);
          close(pipes[0][0]);
          close(pipes[1][1]);
          close(pipes[1][0]);
          close(pipes[0][1]);
          char* argv[] = {strdup(_fzncmd.c_str()),strdup("-a"),strdup("-"),0};
          if (!_canPipe) {
            argv[2] = strdup(fznFile.c_str());
          }
          int status = execvp(argv[0],argv);
          if(status == -1) {
            std::stringstream ssm;
            ssm << "Error occurred when executing FZN solver with command \"" << argv[0] << " " << argv[1] << " " << argv[2] << "\".";
            throw InternalError(ssm.str());
          }
        }
        assert(false);
      }
    };
  }

  FZNSolverInstance::FZNSolverInstance(Env& env, const Options& options)
  : SolverInstanceImpl<FZNSolver>(env,options), _fzn(env.flat()), _ozn(env.output()) {}

  FZNSolverInstance::~FZNSolverInstance(void) {}

  SolverInstance::Status
  FZNSolverInstance::next(void) { return SolverInstance::ERROR; }

  namespace {
    ArrayLit* b_arrayXd(Env& env, ASTExprVec<Expression> args, int d) {
      GCLock lock;
      ArrayLit* al = eval_array_lit(env.envi(), args[d]);
      std::vector<std::pair<int,int> > dims(d);
      unsigned int dim1d = 1;
      for (int i=0; i<d; i++) {
        IntSetVal* di = eval_intset(env.envi(), args[i]);
        if (di->size()==0) {
          dims[i] = std::pair<int,int>(1,0);
          dim1d = 0;
        } else if (di->size() != 1) {
          throw EvalError(env.envi(), args[i]->loc(), "arrayXd only defined for ranges");
        } else {
          dims[i] = std::pair<int,int>(static_cast<int>(di->min(0).toInt()),
                                       static_cast<int>(di->max(0).toInt()));
          dim1d *= dims[i].second-dims[i].first+1;
        }
      }
      if (dim1d != al->v().size())
        throw EvalError(env.envi(), al->loc(), "mismatch in array dimensions");
      ArrayLit* ret = new ArrayLit(al->loc(), al->v(), dims);
      Type t = al->type();
      t.dim(d);
      ret->type(t);
      ret->flat(al->flat());
      return ret;
    }
  }

  SolverInstance::Status
  FZNSolverInstance::solve(void) {
    std::vector<std::string> includePaths;
    std:: string fzn_solver = "fzn-gecode";
    if(_options.hasParam(constants().opts.solver.fzn_solver.str()))
      fzn_solver = _options.getStringParam(constants().opts.solver.fzn_solver.str());
    if(_options.hasParam(constants().opts.verbose.str())) {
      if(_options.getBoolParam(constants().opts.verbose.str()))
        std::cerr << "Using FZN solver " << fzn_solver << " for solving." << std::endl;
    }
    FznProcess proc(fzn_solver,false,_fzn);
    std::string r = proc.run();
    std::stringstream result;
    result << r;
    std::string solution;

    typedef std::pair<VarDecl*,Expression*> DE;
    ASTStringMap<DE>::t declmap;
    for (unsigned int i=0; i<_ozn->size(); i++) {
      if (VarDeclI* vdi = (*_ozn)[i]->dyn_cast<VarDeclI>()) {
        declmap.insert(std::make_pair(vdi->e()->id()->v(),DE(vdi->e(),vdi->e()->e())));
      }
    }

    bool hadSolution = false;
    while (result.good()) {
      std::string line;
      getline(result, line);
      if (line=="----------") {
        if (hadSolution) {
          for (ASTStringMap<DE>::t::iterator it=declmap.begin(); it != declmap.end(); ++it) {
            it->second.first->e(it->second.second);
          }
        }
        Model* sm = parseFromString(solution, "solution.szn", includePaths, true, false, false, std::cerr);
        for (Model::iterator it = sm->begin(); it != sm->end(); ++it) {
          if (AssignI* ai = (*it)->dyn_cast<AssignI>()) {
            ASTStringMap<DE>::t::iterator it = declmap.find(ai->id());
            if (it==declmap.end()) {
              std::cerr << "Error: unexpected identifier " << ai->id() << " in output\n";
              exit(EXIT_FAILURE);
            }
            if (Call* c = ai->e()->dyn_cast<Call>()) {
              // This is an arrayXd call, make sure we get the right builtin
              assert(c->args()[c->args().size()-1]->isa<ArrayLit>());
              for (unsigned int i=0; i<c->args().size(); i++)
                c->args()[i]->type(Type::parsetint());
              c->args()[c->args().size()-1]->type(it->second.first->type());
              ArrayLit* al = b_arrayXd(_env, c->args(), c->args().size()-1);
              it->second.first->e(al);
            } else {
              it->second.first->e(ai->e());
            }
          }
        }
        delete sm;
        hadSolution = true;
      } else if (line=="==========") {
        return hadSolution ? SolverInstance::OPT : SolverInstance::UNSAT;
      } else if(line=="=====UNSATISFIABLE=====") {
        return SolverInstance::UNSAT;
      } else if(line=="=====UNBOUNDED=====") {
        return SolverInstance::UNKNOWN;
      } else if(line=="=====UNKNOWN=====") {
        return SolverInstance::UNKNOWN;
      } else {
        solution += line;
      }
    }

    return hadSolution ? SolverInstance::SAT : SolverInstance::UNSAT;
  }

  void
  FZNSolverInstance::processFlatZinc(void) {}

  void
  FZNSolverInstance::resetSolver(void) {}

  Expression*
  FZNSolverInstance::getSolutionValue(Id* id) {
    assert(false);
  }

}
<|endoftext|>


<commit_before>//===-- SoftwareBreakpoint.cpp ----------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Host/common/SoftwareBreakpoint.h"

#include "lldb/Core/Error.h"
#include "lldb/Core/Log.h"
#include "lldb/Host/Debug.h"
#include "lldb/Host/Mutex.h"

#include "lldb/Host/common/NativeProcessProtocol.h"

using namespace lldb_private;

// -------------------------------------------------------------------
// static members
// -------------------------------------------------------------------

Error
SoftwareBreakpoint::CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_sp)
{
    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
    if (log)
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);

    // Validate the address.
    if (addr == LLDB_INVALID_ADDRESS)
        return Error ("SoftwareBreakpoint::%s invalid load address specified.", __FUNCTION__);

    // Ask the NativeProcessProtocol subclass to fill in the correct software breakpoint
    // trap for the breakpoint site.
    size_t bp_opcode_size = 0;
    const uint8_t *bp_opcode_bytes = NULL;
    Error error = process.GetSoftwareBreakpointTrapOpcode (size_hint, bp_opcode_size, bp_opcode_bytes);

    if (error.Fail ())
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to retrieve software breakpoint trap opcode: %s", __FUNCTION__, error.AsCString ());
        return error;
    }

    // Validate size of trap opcode.
    if (bp_opcode_size == 0)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to retrieve any trap opcodes", __FUNCTION__);
        return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%" PRIx64, addr);
    }

    if (bp_opcode_size > MAX_TRAP_OPCODE_SIZE)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s cannot support %lu trapcode bytes, max size is %lu", __FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
        return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned too many trap opcode bytes: requires %lu but we only support a max of %lu", bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
    }

    // Validate that we received opcodes.
    if (!bp_opcode_bytes)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to retrieve trap opcode bytes", __FUNCTION__);
        return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned NULL trap opcode bytes, unable to get breakpoint trap for address 0x%" PRIx64, addr);
    }

    // Enable the breakpoint.
    uint8_t saved_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
    error = EnableSoftwareBreakpoint (process, addr, bp_opcode_size, bp_opcode_bytes, saved_opcode_bytes);
    if (error.Fail ())
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s: failed to enable new breakpoint at 0x%" PRIx64 ": %s", __FUNCTION__, addr, error.AsCString ());
        return error;
    }

    if (log)
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);

    // Set the breakpoint and verified it was written properly.  Now
    // create a breakpoint remover that understands how to undo this
    // breakpoint.
    breakpoint_sp.reset (new SoftwareBreakpoint (process, addr, saved_opcode_bytes, bp_opcode_bytes, bp_opcode_size));
    return Error ();
}

Error
SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes)
{
    assert (bp_opcode_size <= MAX_TRAP_OPCODE_SIZE && "bp_opcode_size out of valid range");
    assert (bp_opcode_bytes && "bp_opcode_bytes is NULL");
    assert (saved_opcode_bytes && "saved_opcode_bytes is NULL");

    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
    if (log)
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);

    // Save the original opcodes by reading them so we can restore later.
    size_t bytes_read = 0;

    Error error = process.ReadMemory(addr, saved_opcode_bytes, bp_opcode_size, bytes_read);
    if (error.Fail ())
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
        return error;
    }

    // Ensure we read as many bytes as we expected.
    if (bytes_read != bp_opcode_size)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_read);
        return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_read);
    }

    // Log what we read.
    if (log)
    {
        int i = 0;
        for (const uint8_t *read_byte = saved_opcode_bytes; read_byte < saved_opcode_bytes + bp_opcode_size; ++read_byte)
        {
            log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
                    " ovewriting byte index %d (was 0x%hhx)",
                    __FUNCTION__, addr, i++, *read_byte);
        }
    }

    // Write a software breakpoint in place of the original opcode.
    size_t bytes_written = 0;
    error = process.WriteMemory(addr, bp_opcode_bytes, bp_opcode_size, bytes_written);
    if (error.Fail ())
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to write memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
        return error;
    }

    // Ensure we wrote as many bytes as we expected.
    if (bytes_written != bp_opcode_size)
    {
        error.SetErrorStringWithFormat("SoftwareBreakpoint::%s failed write memory while attempting to set breakpoint: attempted to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_written);
        if (log)
            log->PutCString (error.AsCString ());
        return error;
    }

    uint8_t verify_bp_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
    size_t verify_bytes_read = 0;
    error = process.ReadMemory(addr, verify_bp_opcode_bytes, bp_opcode_size, verify_bytes_read);
    if (error.Fail ())
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify the breakpoint set: %s", __FUNCTION__, error.AsCString ());
        return error;
    }

    // Ensure we read as many verification bytes as we expected.
    if (verify_bytes_read != bp_opcode_size)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, verify_bytes_read);
        return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, verify_bytes_read);
    }

    if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
        return Error ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
    }

    if (log)
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);

    return Error ();
}

// -------------------------------------------------------------------
// instance-level members
// -------------------------------------------------------------------

SoftwareBreakpoint::SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size) :
    NativeBreakpoint (addr),
    m_process (process),
    m_saved_opcodes (),
    m_trap_opcodes (),
    m_opcode_size (opcode_size)
{
    assert ( opcode_size > 0 && "setting software breakpoint with no trap opcodes");
    assert ( opcode_size <= MAX_TRAP_OPCODE_SIZE  && "trap opcode size too large");

    ::memcpy (m_saved_opcodes, saved_opcodes, opcode_size);
    ::memcpy (m_trap_opcodes, trap_opcodes, opcode_size);
}

Error
SoftwareBreakpoint::DoEnable ()
{
    return EnableSoftwareBreakpoint (m_process, m_addr, m_opcode_size, m_trap_opcodes, m_saved_opcodes);
}

Error
SoftwareBreakpoint::DoDisable ()
{
    Error error;
    assert (m_addr && (m_addr != LLDB_INVALID_ADDRESS) && "can't remove a software breakpoint for an invalid address");

    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
    if (log)
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, m_addr);

    assert ( (m_opcode_size > 0) && "cannot restore opcodes when there are no opcodes");

    if (m_opcode_size > 0)
    {
        // Clear a software breakpoint instruction
        uint8_t curr_break_op [MAX_TRAP_OPCODE_SIZE];
        bool break_op_found = false;
        assert (m_opcode_size <= sizeof (curr_break_op));

        // Read the breakpoint opcode
        size_t bytes_read = 0;
        error = m_process.ReadMemory (m_addr, curr_break_op, m_opcode_size, bytes_read);
        if (error.Success() && bytes_read < m_opcode_size)
        {
            error.SetErrorStringWithFormat ("SoftwareBreakpointr::%s addr=0x%" PRIx64 ": tried to read %lu bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, bytes_read);
        }
        if (error.Success ())
        {
            bool verify = false;
            // Make sure we have the a breakpoint opcode exists at this address
            if (::memcmp (curr_break_op, m_trap_opcodes, m_opcode_size) == 0)
            {
                break_op_found = true;
                // We found a valid breakpoint opcode at this address, now restore
                // the saved opcode.
                size_t bytes_written = 0;
                error = m_process.WriteMemory (m_addr, m_saved_opcodes, m_opcode_size, bytes_written);
                if (error.Success() && bytes_written < m_opcode_size)
                {
                    error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, bytes_written);
                }
                if (error.Success ())
                {
                    verify = true;
                }
            }
            else
            {
                error.SetErrorString("Original breakpoint trap is no longer in memory.");
                // Set verify to true and so we can check if the original opcode has already been restored
                verify = true;
            }

            if (verify)
            {
                uint8_t verify_opcode [MAX_TRAP_OPCODE_SIZE];
                assert (m_opcode_size <= sizeof (verify_opcode));
                // Verify that our original opcode made it back to the inferior

                size_t verify_bytes_read = 0;
                error = m_process.ReadMemory (m_addr, verify_opcode, m_opcode_size, verify_bytes_read);
                if (error.Success() && verify_bytes_read < m_opcode_size)
                {
                    error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to read %lu verification bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, verify_bytes_read);
                }
                if (error.Success ())
                {
                    // compare the memory we just read with the original opcode
                    if (::memcmp (m_saved_opcodes, verify_opcode, m_opcode_size) == 0)
                    {
                        // SUCCESS
                        if (log)
                        {
                            int i = 0;
                            for (const uint8_t *verify_byte = verify_opcode; verify_byte < verify_opcode + m_opcode_size; ++verify_byte)
                            {
                                log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
                                        " replaced byte index %d with 0x%hhx",
                                        __FUNCTION__, m_addr, i++, *verify_byte);
                            }
                            log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, m_addr);
                        }
                        return error;
                    }
                    else
                    {
                        if (break_op_found)
                            error.SetErrorString("Failed to restore original opcode.");
                    }
                }
                else
                    error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored.");
            }
        }
    }

    if (log && error.Fail ())
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- FAILED: %s",
                __FUNCTION__,
                m_addr,
                error.AsCString());
    return error;
}

bool
SoftwareBreakpoint::IsSoftwareBreakpoint () const
{
    return true;
}

<commit_msg>Fix compiler warnings regarding size_t not always being 64 bit in the printf.<commit_after>//===-- SoftwareBreakpoint.cpp ----------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Host/common/SoftwareBreakpoint.h"

#include "lldb/Core/Error.h"
#include "lldb/Core/Log.h"
#include "lldb/Host/Debug.h"
#include "lldb/Host/Mutex.h"

#include "lldb/Host/common/NativeProcessProtocol.h"

using namespace lldb_private;

// -------------------------------------------------------------------
// static members
// -------------------------------------------------------------------

Error
SoftwareBreakpoint::CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_sp)
{
    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
    if (log)
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);

    // Validate the address.
    if (addr == LLDB_INVALID_ADDRESS)
        return Error ("SoftwareBreakpoint::%s invalid load address specified.", __FUNCTION__);

    // Ask the NativeProcessProtocol subclass to fill in the correct software breakpoint
    // trap for the breakpoint site.
    size_t bp_opcode_size = 0;
    const uint8_t *bp_opcode_bytes = NULL;
    Error error = process.GetSoftwareBreakpointTrapOpcode (size_hint, bp_opcode_size, bp_opcode_bytes);

    if (error.Fail ())
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to retrieve software breakpoint trap opcode: %s", __FUNCTION__, error.AsCString ());
        return error;
    }

    // Validate size of trap opcode.
    if (bp_opcode_size == 0)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to retrieve any trap opcodes", __FUNCTION__);
        return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%" PRIx64, addr);
    }

    if (bp_opcode_size > MAX_TRAP_OPCODE_SIZE)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s cannot support %lu trapcode bytes, max size is %lu", __FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
        return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned too many trap opcode bytes: requires %lu but we only support a max of %lu", bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
    }

    // Validate that we received opcodes.
    if (!bp_opcode_bytes)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to retrieve trap opcode bytes", __FUNCTION__);
        return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned NULL trap opcode bytes, unable to get breakpoint trap for address 0x%" PRIx64, addr);
    }

    // Enable the breakpoint.
    uint8_t saved_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
    error = EnableSoftwareBreakpoint (process, addr, bp_opcode_size, bp_opcode_bytes, saved_opcode_bytes);
    if (error.Fail ())
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s: failed to enable new breakpoint at 0x%" PRIx64 ": %s", __FUNCTION__, addr, error.AsCString ());
        return error;
    }

    if (log)
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);

    // Set the breakpoint and verified it was written properly.  Now
    // create a breakpoint remover that understands how to undo this
    // breakpoint.
    breakpoint_sp.reset (new SoftwareBreakpoint (process, addr, saved_opcode_bytes, bp_opcode_bytes, bp_opcode_size));
    return Error ();
}

Error
SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes)
{
    assert (bp_opcode_size <= MAX_TRAP_OPCODE_SIZE && "bp_opcode_size out of valid range");
    assert (bp_opcode_bytes && "bp_opcode_bytes is NULL");
    assert (saved_opcode_bytes && "saved_opcode_bytes is NULL");

    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
    if (log)
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);

    // Save the original opcodes by reading them so we can restore later.
    size_t bytes_read = 0;

    Error error = process.ReadMemory(addr, saved_opcode_bytes, bp_opcode_size, bytes_read);
    if (error.Fail ())
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
        return error;
    }

    // Ensure we read as many bytes as we expected.
    if (bytes_read != bp_opcode_size)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_read);
        return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_read);
    }

    // Log what we read.
    if (log)
    {
        int i = 0;
        for (const uint8_t *read_byte = saved_opcode_bytes; read_byte < saved_opcode_bytes + bp_opcode_size; ++read_byte)
        {
            log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
                    " ovewriting byte index %d (was 0x%hhx)",
                    __FUNCTION__, addr, i++, *read_byte);
        }
    }

    // Write a software breakpoint in place of the original opcode.
    size_t bytes_written = 0;
    error = process.WriteMemory(addr, bp_opcode_bytes, bp_opcode_size, bytes_written);
    if (error.Fail ())
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to write memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
        return error;
    }

    // Ensure we wrote as many bytes as we expected.
    if (bytes_written != bp_opcode_size)
    {
        error.SetErrorStringWithFormat("SoftwareBreakpoint::%s failed write memory while attempting to set breakpoint: attempted to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_written);
        if (log)
            log->PutCString (error.AsCString ());
        return error;
    }

    uint8_t verify_bp_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
    size_t verify_bytes_read = 0;
    error = process.ReadMemory(addr, verify_bp_opcode_bytes, bp_opcode_size, verify_bytes_read);
    if (error.Fail ())
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify the breakpoint set: %s", __FUNCTION__, error.AsCString ());
        return error;
    }

    // Ensure we read as many verification bytes as we expected.
    if (verify_bytes_read != bp_opcode_size)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)verify_bytes_read);
        return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)verify_bytes_read);
    }

    if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0)
    {
        if (log)
            log->Printf ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
        return Error ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
    }

    if (log)
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);

    return Error ();
}

// -------------------------------------------------------------------
// instance-level members
// -------------------------------------------------------------------

SoftwareBreakpoint::SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size) :
    NativeBreakpoint (addr),
    m_process (process),
    m_saved_opcodes (),
    m_trap_opcodes (),
    m_opcode_size (opcode_size)
{
    assert ( opcode_size > 0 && "setting software breakpoint with no trap opcodes");
    assert ( opcode_size <= MAX_TRAP_OPCODE_SIZE  && "trap opcode size too large");

    ::memcpy (m_saved_opcodes, saved_opcodes, opcode_size);
    ::memcpy (m_trap_opcodes, trap_opcodes, opcode_size);
}

Error
SoftwareBreakpoint::DoEnable ()
{
    return EnableSoftwareBreakpoint (m_process, m_addr, m_opcode_size, m_trap_opcodes, m_saved_opcodes);
}

Error
SoftwareBreakpoint::DoDisable ()
{
    Error error;
    assert (m_addr && (m_addr != LLDB_INVALID_ADDRESS) && "can't remove a software breakpoint for an invalid address");

    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
    if (log)
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, m_addr);

    assert ( (m_opcode_size > 0) && "cannot restore opcodes when there are no opcodes");

    if (m_opcode_size > 0)
    {
        // Clear a software breakpoint instruction
        uint8_t curr_break_op [MAX_TRAP_OPCODE_SIZE];
        bool break_op_found = false;
        assert (m_opcode_size <= sizeof (curr_break_op));

        // Read the breakpoint opcode
        size_t bytes_read = 0;
        error = m_process.ReadMemory (m_addr, curr_break_op, m_opcode_size, bytes_read);
        if (error.Success() && bytes_read < m_opcode_size)
        {
            error.SetErrorStringWithFormat ("SoftwareBreakpointr::%s addr=0x%" PRIx64 ": tried to read %lu bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)bytes_read);
        }
        if (error.Success ())
        {
            bool verify = false;
            // Make sure we have the a breakpoint opcode exists at this address
            if (::memcmp (curr_break_op, m_trap_opcodes, m_opcode_size) == 0)
            {
                break_op_found = true;
                // We found a valid breakpoint opcode at this address, now restore
                // the saved opcode.
                size_t bytes_written = 0;
                error = m_process.WriteMemory (m_addr, m_saved_opcodes, m_opcode_size, bytes_written);
                if (error.Success() && bytes_written < m_opcode_size)
                {
                    error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)bytes_written);
                }
                if (error.Success ())
                {
                    verify = true;
                }
            }
            else
            {
                error.SetErrorString("Original breakpoint trap is no longer in memory.");
                // Set verify to true and so we can check if the original opcode has already been restored
                verify = true;
            }

            if (verify)
            {
                uint8_t verify_opcode [MAX_TRAP_OPCODE_SIZE];
                assert (m_opcode_size <= sizeof (verify_opcode));
                // Verify that our original opcode made it back to the inferior

                size_t verify_bytes_read = 0;
                error = m_process.ReadMemory (m_addr, verify_opcode, m_opcode_size, verify_bytes_read);
                if (error.Success() && verify_bytes_read < m_opcode_size)
                {
                    error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to read %lu verification bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)verify_bytes_read);
                }
                if (error.Success ())
                {
                    // compare the memory we just read with the original opcode
                    if (::memcmp (m_saved_opcodes, verify_opcode, m_opcode_size) == 0)
                    {
                        // SUCCESS
                        if (log)
                        {
                            int i = 0;
                            for (const uint8_t *verify_byte = verify_opcode; verify_byte < verify_opcode + m_opcode_size; ++verify_byte)
                            {
                                log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
                                        " replaced byte index %d with 0x%hhx",
                                        __FUNCTION__, m_addr, i++, *verify_byte);
                            }
                            log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, m_addr);
                        }
                        return error;
                    }
                    else
                    {
                        if (break_op_found)
                            error.SetErrorString("Failed to restore original opcode.");
                    }
                }
                else
                    error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored.");
            }
        }
    }

    if (log && error.Fail ())
        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- FAILED: %s",
                __FUNCTION__,
                m_addr,
                error.AsCString());
    return error;
}

bool
SoftwareBreakpoint::IsSoftwareBreakpoint () const
{
    return true;
}

<|endoftext|>


<commit_before>
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "SandSimulator.h"
#include "../World.h"
#include "../BlockID.h"
#include "../Defines.h"
#include "../FallingBlock.h"
#include "../Chunk.h"

cSandSimulator::cSandSimulator(cWorld & a_World, cIniFile & a_IniFile) :
	cSimulator(a_World),
	m_TotalBlocks(0)
{
	m_IsInstantFall = a_IniFile.GetValueSetB("Physics", "SandInstantFall", false);
}

void cSandSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
{
	cSandSimulatorChunkData & ChunkData = a_Chunk->GetSandSimulatorData();
	if (ChunkData.empty())
	{
		return;
	}

	int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
	int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;
	for (cSandSimulatorChunkData::const_iterator itr = ChunkData.begin(), end = ChunkData.end(); itr != end; ++itr)
	{
		BLOCKTYPE BlockType = a_Chunk->GetBlock(itr->x, itr->y, itr->z);
		if (!IsAllowedBlock(BlockType) || (itr->y <= 0))
		{
			continue;
		}

		BLOCKTYPE BlockBelow = (itr->y > 0) ? a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z) : E_BLOCK_AIR;
		if (CanStartFallingThrough(BlockBelow))
		{
			if (m_IsInstantFall)
			{
				DoInstantFall(a_Chunk, itr->x, itr->y, itr->z);
				continue;
			}
			Vector3i Pos;
			Pos.x = itr->x + BaseX;
			Pos.y = itr->y;
			Pos.z = itr->z + BaseZ;
			cFallingBlock * FallingBlock = new cFallingBlock(Pos, BlockType, a_Chunk->GetMeta(itr->x, itr->y, itr->z));
			FallingBlock->Initialize(&m_World);
			a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0);
		}
	}
	m_TotalBlocks -= ChunkData.size();
	ChunkData.clear();
}

bool cSandSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_SAND:
		case E_BLOCK_GRAVEL:
		case E_BLOCK_ANVIL:
		{
			return true;
		}
	}
	return false;
}

void cSandSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
{
	if (a_Chunk == NULL)
	{
		return;
	}
	int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
	int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
	if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_BlockY, RelZ)))
	{
		return;
	}

	// Check for duplicates:
	cSandSimulatorChunkData & ChunkData = a_Chunk->GetSandSimulatorData();
	for (cSandSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr)
	{
		if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ))
		{
			return;
		}
	}

	m_TotalBlocks += 1;
	ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ));
}

bool cSandSimulator::CanStartFallingThrough(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_AIR:
		case E_BLOCK_FIRE:
		case E_BLOCK_LAVA:
		case E_BLOCK_STATIONARY_LAVA:
		case E_BLOCK_STATIONARY_WATER:
		case E_BLOCK_WATER:
		{
			return true;
		}
	}
	return false;
}

bool cSandSimulator::CanContinueFallThrough(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_AIR:
		case E_BLOCK_BROWN_MUSHROOM:
		case E_BLOCK_COBWEB:
		case E_BLOCK_CROPS:
		case E_BLOCK_DEAD_BUSH:
		case E_BLOCK_DETECTOR_RAIL:
		case E_BLOCK_FIRE:
		case E_BLOCK_FLOWER_POT:
		case E_BLOCK_LAVA:
		case E_BLOCK_LEVER:
		case E_BLOCK_MINECART_TRACKS:
		case E_BLOCK_MELON_STEM:
		case E_BLOCK_POWERED_RAIL:
		case E_BLOCK_PUMPKIN_STEM:
		case E_BLOCK_REDSTONE_REPEATER_OFF:
		case E_BLOCK_REDSTONE_REPEATER_ON:
		case E_BLOCK_REDSTONE_TORCH_OFF:
		case E_BLOCK_REDSTONE_TORCH_ON:
		case E_BLOCK_REDSTONE_WIRE:
		case E_BLOCK_RED_MUSHROOM:
		case E_BLOCK_RED_ROSE:
		case E_BLOCK_SIGN_POST:
		case E_BLOCK_STATIONARY_LAVA:
		case E_BLOCK_STATIONARY_WATER:
		case E_BLOCK_STONE_BUTTON:
		case E_BLOCK_STONE_PRESSURE_PLATE:
		case E_BLOCK_TALL_GRASS:
		case E_BLOCK_TORCH:
		case E_BLOCK_TRAPDOOR:
		case E_BLOCK_TRIPWIRE:
		case E_BLOCK_TRIPWIRE_HOOK:
		case E_BLOCK_WALLSIGN:
		case E_BLOCK_WATER:
		case E_BLOCK_WOODEN_BUTTON:
		case E_BLOCK_WOODEN_PRESSURE_PLATE:
		case E_BLOCK_YELLOW_FLOWER:
		{
			return true;
		}
	}
	return false;
}

bool cSandSimulator::IsReplacedOnRematerialization(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_AIR:
		case E_BLOCK_DEAD_BUSH:
		case E_BLOCK_FIRE:
		case E_BLOCK_LAVA:
		case E_BLOCK_STATIONARY_LAVA:
		case E_BLOCK_STATIONARY_WATER:
		case E_BLOCK_TALL_GRASS:
		case E_BLOCK_WATER:
		{
			return true;
		}
	}
	return false;
}

bool cSandSimulator::DoesBreakFallingThrough(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
	switch (a_BlockType)
	{
		case E_BLOCK_STONE_SLAB:
		case E_BLOCK_WOODEN_SLAB:
		{
			return ((a_BlockMeta & 0x08) == 0);  // Only a bottom-slab breaks the block
		}
	}
	return false;
}

void cSandSimulator::FinishFalling(
	cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ,
	BLOCKTYPE a_FallingBlockType, NIBBLETYPE a_FallingBlockMeta
)
{
	ASSERT(a_BlockY < cChunkDef::Height);

	BLOCKTYPE CurrentBlockType = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
	if ((a_FallingBlockType == E_BLOCK_ANVIL) || IsReplacedOnRematerialization(CurrentBlockType))
	{
		// Rematerialize the material here:
		a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FallingBlockType, a_FallingBlockMeta);
		return;
	}

	// Create a pickup instead:
	cItems Pickups;
	Pickups.Add((ENUM_ITEM_ID)a_FallingBlockType, 1, a_FallingBlockMeta);
	a_World->SpawnItemPickups(Pickups, (double)a_BlockX + 0.5, (double)a_BlockY + 0.5, (double)a_BlockZ + 0.5, 0);
}

void cSandSimulator::DoInstantFall(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
{
	// Remove the original block:
	BLOCKTYPE  FallingBlockType;
	NIBBLETYPE FallingBlockMeta;
	a_Chunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, FallingBlockType, FallingBlockMeta);
	a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0);

	// Search for a place to put it:
	for (int y = a_RelY - 1; y >= 0; y--)
	{
		BLOCKTYPE BlockType;
		NIBBLETYPE BlockMeta;
		a_Chunk->GetBlockTypeMeta(a_RelX, y, a_RelZ, BlockType, BlockMeta);
		int BlockY;
		if (DoesBreakFallingThrough(BlockType, BlockMeta))
		{
			BlockY = y;
		}
		else if (!CanContinueFallThrough(BlockType))
		{
			BlockY = y + 1;
		}
		else
		{
			// Can fall further down
			continue;
		}

		// Finish the fall at the found bottom:
		int BlockX = a_RelX + a_Chunk->GetPosX() * cChunkDef::Width;
		int BlockZ = a_RelZ + a_Chunk->GetPosZ() * cChunkDef::Width;
		FinishFalling(&m_World, BlockX, BlockY, BlockZ, FallingBlockType, FallingBlockMeta);
		return;
	}

	// The block just "fell off the world" without leaving a trace
}

<commit_msg>Sand can fall through snow. Patch courtesy of InHavk<commit_after>
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "SandSimulator.h"
#include "../World.h"
#include "../BlockID.h"
#include "../Defines.h"
#include "../FallingBlock.h"
#include "../Chunk.h"

cSandSimulator::cSandSimulator(cWorld & a_World, cIniFile & a_IniFile) :
	cSimulator(a_World),
	m_TotalBlocks(0)
{
	m_IsInstantFall = a_IniFile.GetValueSetB("Physics", "SandInstantFall", false);
}

void cSandSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
{
	cSandSimulatorChunkData & ChunkData = a_Chunk->GetSandSimulatorData();
	if (ChunkData.empty())
	{
		return;
	}

	int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
	int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;
	for (cSandSimulatorChunkData::const_iterator itr = ChunkData.begin(), end = ChunkData.end(); itr != end; ++itr)
	{
		BLOCKTYPE BlockType = a_Chunk->GetBlock(itr->x, itr->y, itr->z);
		if (!IsAllowedBlock(BlockType) || (itr->y <= 0))
		{
			continue;
		}

		BLOCKTYPE BlockBelow = (itr->y > 0) ? a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z) : E_BLOCK_AIR;
		if (CanStartFallingThrough(BlockBelow))
		{
			if (m_IsInstantFall)
			{
				DoInstantFall(a_Chunk, itr->x, itr->y, itr->z);
				continue;
			}
			Vector3i Pos;
			Pos.x = itr->x + BaseX;
			Pos.y = itr->y;
			Pos.z = itr->z + BaseZ;
			cFallingBlock * FallingBlock = new cFallingBlock(Pos, BlockType, a_Chunk->GetMeta(itr->x, itr->y, itr->z));
			FallingBlock->Initialize(&m_World);
			a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0);
		}
	}
	m_TotalBlocks -= ChunkData.size();
	ChunkData.clear();
}

bool cSandSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_SAND:
		case E_BLOCK_GRAVEL:
		case E_BLOCK_ANVIL:
		{
			return true;
		}
	}
	return false;
}

void cSandSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
{
	if (a_Chunk == NULL)
	{
		return;
	}
	int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
	int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
	if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_BlockY, RelZ)))
	{
		return;
	}

	// Check for duplicates:
	cSandSimulatorChunkData & ChunkData = a_Chunk->GetSandSimulatorData();
	for (cSandSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr)
	{
		if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ))
		{
			return;
		}
	}

	m_TotalBlocks += 1;
	ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ));
}

bool cSandSimulator::CanStartFallingThrough(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_AIR:
		case E_BLOCK_FIRE:
		case E_BLOCK_LAVA:
		case E_BLOCK_STATIONARY_LAVA:
		case E_BLOCK_STATIONARY_WATER:
		case E_BLOCK_WATER:
		case E_BLOCK_SNOW:
		{
			return true;
		}
	}
	return false;
}

bool cSandSimulator::CanContinueFallThrough(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_AIR:
		case E_BLOCK_BROWN_MUSHROOM:
		case E_BLOCK_COBWEB:
		case E_BLOCK_CROPS:
		case E_BLOCK_DEAD_BUSH:
		case E_BLOCK_DETECTOR_RAIL:
		case E_BLOCK_FIRE:
		case E_BLOCK_FLOWER_POT:
		case E_BLOCK_LAVA:
		case E_BLOCK_LEVER:
		case E_BLOCK_MINECART_TRACKS:
		case E_BLOCK_MELON_STEM:
		case E_BLOCK_POWERED_RAIL:
		case E_BLOCK_PUMPKIN_STEM:
		case E_BLOCK_REDSTONE_REPEATER_OFF:
		case E_BLOCK_REDSTONE_REPEATER_ON:
		case E_BLOCK_REDSTONE_TORCH_OFF:
		case E_BLOCK_REDSTONE_TORCH_ON:
		case E_BLOCK_REDSTONE_WIRE:
		case E_BLOCK_RED_MUSHROOM:
		case E_BLOCK_RED_ROSE:
		case E_BLOCK_SIGN_POST:
		case E_BLOCK_STATIONARY_LAVA:
		case E_BLOCK_STATIONARY_WATER:
		case E_BLOCK_STONE_BUTTON:
		case E_BLOCK_STONE_PRESSURE_PLATE:
		case E_BLOCK_TALL_GRASS:
		case E_BLOCK_TORCH:
		case E_BLOCK_TRAPDOOR:
		case E_BLOCK_TRIPWIRE:
		case E_BLOCK_TRIPWIRE_HOOK:
		case E_BLOCK_WALLSIGN:
		case E_BLOCK_WATER:
		case E_BLOCK_WOODEN_BUTTON:
		case E_BLOCK_WOODEN_PRESSURE_PLATE:
		case E_BLOCK_YELLOW_FLOWER:
		case E_BLOCK_SNOW:
		{
			return true;
		}
	}
	return false;
}

bool cSandSimulator::IsReplacedOnRematerialization(BLOCKTYPE a_BlockType)
{
	switch (a_BlockType)
	{
		case E_BLOCK_AIR:
		case E_BLOCK_DEAD_BUSH:
		case E_BLOCK_FIRE:
		case E_BLOCK_LAVA:
		case E_BLOCK_STATIONARY_LAVA:
		case E_BLOCK_STATIONARY_WATER:
		case E_BLOCK_TALL_GRASS:
		case E_BLOCK_WATER:
		case E_BLOCK_SNOW:
		{
			return true;
		}
	}
	return false;
}

bool cSandSimulator::DoesBreakFallingThrough(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
	switch (a_BlockType)
	{
		case E_BLOCK_STONE_SLAB:
		case E_BLOCK_WOODEN_SLAB:
		{
			return ((a_BlockMeta & 0x08) == 0);  // Only a bottom-slab breaks the block
		}
	}
	return false;
}

void cSandSimulator::FinishFalling(
	cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ,
	BLOCKTYPE a_FallingBlockType, NIBBLETYPE a_FallingBlockMeta
)
{
	ASSERT(a_BlockY < cChunkDef::Height);

	BLOCKTYPE CurrentBlockType = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
	if ((a_FallingBlockType == E_BLOCK_ANVIL) || IsReplacedOnRematerialization(CurrentBlockType))
	{
		// Rematerialize the material here:
		a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FallingBlockType, a_FallingBlockMeta);
		return;
	}

	// Create a pickup instead:
	cItems Pickups;
	Pickups.Add((ENUM_ITEM_ID)a_FallingBlockType, 1, a_FallingBlockMeta);
	a_World->SpawnItemPickups(Pickups, (double)a_BlockX + 0.5, (double)a_BlockY + 0.5, (double)a_BlockZ + 0.5, 0);
}

void cSandSimulator::DoInstantFall(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
{
	// Remove the original block:
	BLOCKTYPE  FallingBlockType;
	NIBBLETYPE FallingBlockMeta;
	a_Chunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, FallingBlockType, FallingBlockMeta);
	a_Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0);

	// Search for a place to put it:
	for (int y = a_RelY - 1; y >= 0; y--)
	{
		BLOCKTYPE BlockType;
		NIBBLETYPE BlockMeta;
		a_Chunk->GetBlockTypeMeta(a_RelX, y, a_RelZ, BlockType, BlockMeta);
		int BlockY;
		if (DoesBreakFallingThrough(BlockType, BlockMeta))
		{
			BlockY = y;
		}
		else if (!CanContinueFallThrough(BlockType))
		{
			BlockY = y + 1;
		}
		else
		{
			// Can fall further down
			continue;
		}

		// Finish the fall at the found bottom:
		int BlockX = a_RelX + a_Chunk->GetPosX() * cChunkDef::Width;
		int BlockZ = a_RelZ + a_Chunk->GetPosZ() * cChunkDef::Width;
		FinishFalling(&m_World, BlockX, BlockY, BlockZ, FallingBlockType, FallingBlockMeta);
		return;
	}

	// The block just "fell off the world" without leaving a trace
}

<|endoftext|>