<commit_before>/* Tree View/Editable Cells
 *
 * This demo demonstrates the use of editable cells in a Gtk::TreeView. If
 * you're new to the Gtk::TreeView widgets and associates, look into
 * the Gtk::ListStore example first.
 *
 */

#include <cstdlib>
#include <gtkmm.h>

class CellItem_Product
{
public:
  CellItem_Product();
  CellItem_Product(const CellItem_Product& src);
  ~CellItem_Product();
  CellItem_Product& operator=(const CellItem_Product& src);

  int m_number;
  Glib::ustring m_product;
};

class Example_TreeView_EditableCells : public Gtk::Window
{
public:
  Example_TreeView_EditableCells();
  ~Example_TreeView_EditableCells() override;

protected:
  //signal handlers:
  virtual void on_button_add_clicked();
  virtual void on_button_remove_clicked();

  virtual void create_model();
  virtual void add_columns();
  virtual void add_items();
  virtual void liststore_add_item(const CellItem_Product& foo);

  //We only have these signal handlers here, because the append_column_editable() convenience methods do not work with
  //the IRIX MipsPro compiler.
  virtual void on_column_number_edited(const Glib::ustring& path_string, const Glib::ustring& new_text);
  virtual void on_column_product_edited(const Glib::ustring& path_string, const Glib::ustring& new_text);

  //Member widgets:
  Gtk::Box m_VBox;
  Gtk::ScrolledWindow m_ScrolledWindow;
  Gtk::Label m_Label;
  Gtk::TreeView m_TreeView;
  Glib::RefPtr<Gtk::ListStore> m_refListStore;
  Gtk::Box m_HBox;
  Gtk::Button m_Button_Add, m_Button_Remove;

  typedef std::vector<CellItem_Product> type_vecItems;
  type_vecItems m_vecItems;

  struct ModelColumns : public Gtk::TreeModelColumnRecord
  {
    Gtk::TreeModelColumn<int>           number;
    Gtk::TreeModelColumn<Glib::ustring> product;

    ModelColumns() { add(number); add(product); }
  };

  const ModelColumns m_columns;
};

CellItem_Product::CellItem_Product()
{
  m_number = 0;
}

CellItem_Product::CellItem_Product(const CellItem_Product& src)
{
  operator=(src);
}

CellItem_Product::~CellItem_Product()
{
}

CellItem_Product& CellItem_Product::operator=(const CellItem_Product& src)
{
  m_number = src.m_number;
  m_product = src.m_product;

  return *this;
}

//Called by DemoWindow;
Gtk::Window* do_treeview_editable_cells()
{
  return new Example_TreeView_EditableCells();
}

Example_TreeView_EditableCells::Example_TreeView_EditableCells()
: m_VBox(Gtk::ORIENTATION_VERTICAL, 5),
  m_Label("Shopping list (you can edit the cells!)"),
  m_HBox(Gtk::ORIENTATION_HORIZONTAL, 4),
  m_Button_Add("Add item"),
  m_Button_Remove("Remove item")
{
  set_title("Shopping List");
  set_border_width(5);
  set_default_size(320, 200);

  add(m_VBox);
  m_VBox.pack_start(m_Label, Gtk::PACK_SHRINK);

  m_ScrolledWindow.set_shadow_type(Gtk::SHADOW_ETCHED_IN);
  m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  m_VBox.pack_start(m_ScrolledWindow);

  /* create model */
  create_model();

  /* create tree view */
  m_TreeView.set_model(m_refListStore);
  Glib::RefPtr<Gtk::TreeSelection> refTreeSelection = m_TreeView.get_selection();
  refTreeSelection->set_mode(Gtk::SELECTION_SINGLE);

  add_columns();
  m_ScrolledWindow.add(m_TreeView);

  /* some buttons */
  m_VBox.pack_start(m_HBox, Gtk::PACK_SHRINK);

  m_HBox.pack_start(m_Button_Add);
  m_Button_Add.signal_clicked().connect(
    sigc::mem_fun(*this, &Example_TreeView_EditableCells::on_button_add_clicked));

  m_HBox.pack_start(m_Button_Remove);
  m_Button_Remove.signal_clicked().connect(
    sigc::mem_fun(*this, &Example_TreeView_EditableCells::on_button_remove_clicked));

  show_all();
}

Example_TreeView_EditableCells::~Example_TreeView_EditableCells()
{
}

void Example_TreeView_EditableCells::add_items()
{
  CellItem_Product foo;

  foo.m_number = 3;
  foo.m_product = "bottles of coke";
  m_vecItems.push_back(foo);

  foo.m_number = 5;
  foo.m_product = "packages of noodles";
  m_vecItems.push_back(foo);

  foo.m_number = 2;
  foo.m_product = "packages of chocolate chip cookies";
  m_vecItems.push_back(foo);

  foo.m_number = 1;
  foo.m_product = "can vanilla ice cream";
  m_vecItems.push_back(foo);

  foo.m_number = 6;
  foo.m_product = "eggs";
  m_vecItems.push_back(foo);
}

void Example_TreeView_EditableCells::create_model()
{
  m_refListStore = Gtk::ListStore::create(m_columns);

  /* add items */
  add_items();

  std::for_each(
      m_vecItems.begin(), m_vecItems.end(),
      sigc::mem_fun(*this, &Example_TreeView_EditableCells::liststore_add_item));
}

void Example_TreeView_EditableCells::liststore_add_item(const CellItem_Product& foo)
{
  Gtk::TreeRow row = *(m_refListStore->append());

  row[m_columns.number]   = foo.m_number;
  row[m_columns.product]  = foo.m_product;
}

//We only have these signal handlers here, because the append_column_editable() convenience methods do not work with
//the IRIX MipsPro compiler.
void Example_TreeView_EditableCells::on_column_number_edited(const Glib::ustring& path_string, const Glib::ustring& new_text)
{
  Gtk::TreePath path(path_string);

  //Get the row from the path:
  Glib::RefPtr<Gtk::TreeModel> refModel = m_TreeView.get_model();
  if(refModel)
  {
    Gtk::TreeModel::iterator iter = refModel->get_iter(path);
    if(iter)
    {
      //Convert the text to a number, using the same logic used by GtkCellRendererText when it stores numbers.
      auto new_value = std::stoi(new_text);

      //Store the user's new text in the model:
      Gtk::TreeRow row = *iter;
      row[m_columns.number] = new_value;
    }
  }
}

void Example_TreeView_EditableCells::on_column_product_edited(const Glib::ustring& path_string, const Glib::ustring& new_text)
{
  Gtk::TreePath path(path_string);

  //Get the row from the path:
  Glib::RefPtr<Gtk::TreeModel> refModel = m_TreeView.get_model();
  if(refModel)
  {
    Gtk::TreeModel::iterator iter = refModel->get_iter(path);
    if(iter)
    {
        //Store the user's new text in the model:
        Gtk::TreeRow row = *iter;
        row[m_columns.product] = new_text;
    }
  }
}

void Example_TreeView_EditableCells::add_columns()
{
  //This is the wasy way:
  // number column:
  //m_TreeView.append_column_editable("Number", m_columns.number);
  //
  // product column:
  //m_TreeView.append_column_editable("Product", m_columns.product);

  //And this is the way that works with the IRIX MipsPro compiler too:
  {
    Gtk::TreeView::Column* pViewColumn = Gtk::manage(new Gtk::TreeView::Column("Number", m_columns.number));

    //connect signal handlers for auto-storing of edited cell data
    Gtk::CellRenderer* pCellRenderer = pViewColumn->get_first_cell();
    Gtk::CellRendererText* pCellRenderText = dynamic_cast<Gtk::CellRendererText*>(pCellRenderer);
    if(pCellRenderText)
    {
      //Set the appropriate property,
      pCellRenderText->property_editable() = true;

      //Connect to the appropriate signal, sending the model_column too,
      pCellRenderText->signal_edited().connect( sigc::mem_fun(*this, &Example_TreeView_EditableCells::on_column_number_edited) );
    }

    m_TreeView.append_column(*pViewColumn);
  }

  {
    Gtk::TreeView::Column* pViewColumn = Gtk::manage(new Gtk::TreeView::Column("Product", m_columns.product));

    //connect signal handlers for auto-storing of edited cell data
    Gtk::CellRenderer* pCellRenderer = pViewColumn->get_first_cell();
    Gtk::CellRendererText* pCellRenderText = dynamic_cast<Gtk::CellRendererText*>(pCellRenderer);
    if(pCellRenderText)
    {
      //Set the appropriate property,
      pCellRenderText->property_editable() = true;

      //Connect to the appropriate signal, sending the model_column too,
      pCellRenderText->signal_edited().connect( sigc::mem_fun(*this, &Example_TreeView_EditableCells::on_column_product_edited) );
    }

    m_TreeView.append_column(*pViewColumn);
  }

}

void Example_TreeView_EditableCells::on_button_add_clicked()
{
  CellItem_Product foo;
  foo.m_number = 0;
  foo.m_product = "Description here";
  m_vecItems.push_back(foo);

  liststore_add_item(foo);
}

void Example_TreeView_EditableCells::on_button_remove_clicked()
{
  Glib::RefPtr<Gtk::TreeSelection> refSelection = m_TreeView.get_selection();

  if(const Gtk::TreeModel::iterator iter = refSelection->get_selected())
  {
    const Gtk::TreeModel::Path path(iter);
    const unsigned int index = path.front();

    // Remove item from ListStore:
    m_refListStore->erase(iter);

    // Remove item from vecItems.
    if(index < m_vecItems.size())
      m_vecItems.erase(m_vecItems.begin() + index);
  }
}
<commit_msg>treeview_editable_cells demo: Catch exception from std::stoi<commit_after>/* Tree View/Editable Cells
 *
 * This demo demonstrates the use of editable cells in a Gtk::TreeView. If
 * you're new to the Gtk::TreeView widgets and associates, look into
 * the Gtk::ListStore example first.
 *
 */

#include <cstdlib>
#include <iostream>
#include <gtkmm.h>

class CellItem_Product
{
public:
  CellItem_Product();
  CellItem_Product(const CellItem_Product& src);
  ~CellItem_Product();
  CellItem_Product& operator=(const CellItem_Product& src);

  int m_number;
  Glib::ustring m_product;
};

class Example_TreeView_EditableCells : public Gtk::Window
{
public:
  Example_TreeView_EditableCells();
  ~Example_TreeView_EditableCells() override;

protected:
  //signal handlers:
  virtual void on_button_add_clicked();
  virtual void on_button_remove_clicked();

  virtual void create_model();
  virtual void add_columns();
  virtual void add_items();
  virtual void liststore_add_item(const CellItem_Product& foo);

  //We only have these signal handlers here, because the append_column_editable() convenience methods do not work with
  //the IRIX MipsPro compiler.
  virtual void on_column_number_edited(const Glib::ustring& path_string, const Glib::ustring& new_text);
  virtual void on_column_product_edited(const Glib::ustring& path_string, const Glib::ustring& new_text);

  //Member widgets:
  Gtk::Box m_VBox;
  Gtk::ScrolledWindow m_ScrolledWindow;
  Gtk::Label m_Label;
  Gtk::TreeView m_TreeView;
  Glib::RefPtr<Gtk::ListStore> m_refListStore;
  Gtk::Box m_HBox;
  Gtk::Button m_Button_Add, m_Button_Remove;

  typedef std::vector<CellItem_Product> type_vecItems;
  type_vecItems m_vecItems;

  struct ModelColumns : public Gtk::TreeModelColumnRecord
  {
    Gtk::TreeModelColumn<int>           number;
    Gtk::TreeModelColumn<Glib::ustring> product;

    ModelColumns() { add(number); add(product); }
  };

  const ModelColumns m_columns;
};

CellItem_Product::CellItem_Product()
{
  m_number = 0;
}

CellItem_Product::CellItem_Product(const CellItem_Product& src)
{
  operator=(src);
}

CellItem_Product::~CellItem_Product()
{
}

CellItem_Product& CellItem_Product::operator=(const CellItem_Product& src)
{
  m_number = src.m_number;
  m_product = src.m_product;

  return *this;
}

//Called by DemoWindow;
Gtk::Window* do_treeview_editable_cells()
{
  return new Example_TreeView_EditableCells();
}

Example_TreeView_EditableCells::Example_TreeView_EditableCells()
: m_VBox(Gtk::ORIENTATION_VERTICAL, 5),
  m_Label("Shopping list (you can edit the cells!)"),
  m_HBox(Gtk::ORIENTATION_HORIZONTAL, 4),
  m_Button_Add("Add item"),
  m_Button_Remove("Remove item")
{
  set_title("Shopping List");
  set_border_width(5);
  set_default_size(320, 200);

  add(m_VBox);
  m_VBox.pack_start(m_Label, Gtk::PACK_SHRINK);

  m_ScrolledWindow.set_shadow_type(Gtk::SHADOW_ETCHED_IN);
  m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  m_VBox.pack_start(m_ScrolledWindow);

  /* create model */
  create_model();

  /* create tree view */
  m_TreeView.set_model(m_refListStore);
  Glib::RefPtr<Gtk::TreeSelection> refTreeSelection = m_TreeView.get_selection();
  refTreeSelection->set_mode(Gtk::SELECTION_SINGLE);

  add_columns();
  m_ScrolledWindow.add(m_TreeView);

  /* some buttons */
  m_VBox.pack_start(m_HBox, Gtk::PACK_SHRINK);

  m_HBox.pack_start(m_Button_Add);
  m_Button_Add.signal_clicked().connect(
    sigc::mem_fun(*this, &Example_TreeView_EditableCells::on_button_add_clicked));

  m_HBox.pack_start(m_Button_Remove);
  m_Button_Remove.signal_clicked().connect(
    sigc::mem_fun(*this, &Example_TreeView_EditableCells::on_button_remove_clicked));

  show_all();
}

Example_TreeView_EditableCells::~Example_TreeView_EditableCells()
{
}

void Example_TreeView_EditableCells::add_items()
{
  CellItem_Product foo;

  foo.m_number = 3;
  foo.m_product = "bottles of coke";
  m_vecItems.push_back(foo);

  foo.m_number = 5;
  foo.m_product = "packages of noodles";
  m_vecItems.push_back(foo);

  foo.m_number = 2;
  foo.m_product = "packages of chocolate chip cookies";
  m_vecItems.push_back(foo);

  foo.m_number = 1;
  foo.m_product = "can vanilla ice cream";
  m_vecItems.push_back(foo);

  foo.m_number = 6;
  foo.m_product = "eggs";
  m_vecItems.push_back(foo);
}

void Example_TreeView_EditableCells::create_model()
{
  m_refListStore = Gtk::ListStore::create(m_columns);

  /* add items */
  add_items();

  std::for_each(
      m_vecItems.begin(), m_vecItems.end(),
      sigc::mem_fun(*this, &Example_TreeView_EditableCells::liststore_add_item));
}

void Example_TreeView_EditableCells::liststore_add_item(const CellItem_Product& foo)
{
  Gtk::TreeRow row = *(m_refListStore->append());

  row[m_columns.number]   = foo.m_number;
  row[m_columns.product]  = foo.m_product;
}

//We only have these signal handlers here, because the append_column_editable() convenience methods do not work with
//the IRIX MipsPro compiler.
void Example_TreeView_EditableCells::on_column_number_edited(const Glib::ustring& path_string, const Glib::ustring& new_text)
{
  Gtk::TreePath path(path_string);

  //Get the row from the path:
  Glib::RefPtr<Gtk::TreeModel> refModel = m_TreeView.get_model();
  if(refModel)
  {
    Gtk::TreeModel::iterator iter = refModel->get_iter(path);
    if(iter)
    {
      //Convert the text to a number, using the same logic used by GtkCellRendererText when it stores numbers.
      int new_value = 0;
      try
      {
        new_value = std::stoi(new_text);
      }
      catch (const std::exception& err)
      {
        std::cout << "Could not convert \"" << new_text << "\" to an integer. ("
          << err.what() << ")" << std::endl;
      }

      //Store the user's new text in the model:
      Gtk::TreeRow row = *iter;
      row[m_columns.number] = new_value;
    }
  }
}

void Example_TreeView_EditableCells::on_column_product_edited(const Glib::ustring& path_string, const Glib::ustring& new_text)
{
  Gtk::TreePath path(path_string);

  //Get the row from the path:
  Glib::RefPtr<Gtk::TreeModel> refModel = m_TreeView.get_model();
  if(refModel)
  {
    Gtk::TreeModel::iterator iter = refModel->get_iter(path);
    if(iter)
    {
        //Store the user's new text in the model:
        Gtk::TreeRow row = *iter;
        row[m_columns.product] = new_text;
    }
  }
}

void Example_TreeView_EditableCells::add_columns()
{
  //This is the wasy way:
  // number column:
  //m_TreeView.append_column_editable("Number", m_columns.number);
  //
  // product column:
  //m_TreeView.append_column_editable("Product", m_columns.product);

  //And this is the way that works with the IRIX MipsPro compiler too:
  {
    Gtk::TreeView::Column* pViewColumn = Gtk::manage(new Gtk::TreeView::Column("Number", m_columns.number));

    //connect signal handlers for auto-storing of edited cell data
    Gtk::CellRenderer* pCellRenderer = pViewColumn->get_first_cell();
    Gtk::CellRendererText* pCellRenderText = dynamic_cast<Gtk::CellRendererText*>(pCellRenderer);
    if(pCellRenderText)
    {
      //Set the appropriate property,
      pCellRenderText->property_editable() = true;

      //Connect to the appropriate signal, sending the model_column too,
      pCellRenderText->signal_edited().connect( sigc::mem_fun(*this, &Example_TreeView_EditableCells::on_column_number_edited) );
    }

    m_TreeView.append_column(*pViewColumn);
  }

  {
    Gtk::TreeView::Column* pViewColumn = Gtk::manage(new Gtk::TreeView::Column("Product", m_columns.product));

    //connect signal handlers for auto-storing of edited cell data
    Gtk::CellRenderer* pCellRenderer = pViewColumn->get_first_cell();
    Gtk::CellRendererText* pCellRenderText = dynamic_cast<Gtk::CellRendererText*>(pCellRenderer);
    if(pCellRenderText)
    {
      //Set the appropriate property,
      pCellRenderText->property_editable() = true;

      //Connect to the appropriate signal, sending the model_column too,
      pCellRenderText->signal_edited().connect( sigc::mem_fun(*this, &Example_TreeView_EditableCells::on_column_product_edited) );
    }

    m_TreeView.append_column(*pViewColumn);
  }

}

void Example_TreeView_EditableCells::on_button_add_clicked()
{
  CellItem_Product foo;
  foo.m_number = 0;
  foo.m_product = "Description here";
  m_vecItems.push_back(foo);

  liststore_add_item(foo);
}

void Example_TreeView_EditableCells::on_button_remove_clicked()
{
  Glib::RefPtr<Gtk::TreeSelection> refSelection = m_TreeView.get_selection();

  if(const Gtk::TreeModel::iterator iter = refSelection->get_selected())
  {
    const Gtk::TreeModel::Path path(iter);
    const unsigned int index = path.front();

    // Remove item from ListStore:
    m_refListStore->erase(iter);

    // Remove item from vecItems.
    if(index < m_vecItems.size())
      m_vecItems.erase(m_vecItems.begin() + index);
  }
}
<|endoftext|>


<commit_before>#include "itkWin32Header.h"
#include <iostream>
#include <fstream>
#include "itkNumericTraits.h"
#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkExtractImageFilter.h"
#include "itkDifferenceImageFilter.h"

using namespace std;

#define ITK_TEST_DIMENSION_MAX 6

int RegressionTestImage(const char *, const char *, int, bool);

int main(int argc, char * *argv)
{
  if( argc < 3 )
    {
    cerr << "Usage:" << endl;
    cerr << "testImage, baselineImage1, [baselineImage2, baselineImage3, ...]" << endl;
    cerr << "Note that if you supply more than one baselineImage, this test will pass if any" << endl;
    cerr << "of them match the testImage" << endl;
    return -1;
    }
  int bestBaselineStatus = 2001;
  int bestBaseline = 2;
  try
    {
    if( argc == 3 )
      {
      bestBaselineStatus = RegressionTestImage(argv[1], argv[2], 0, false);
      }
    else
      {
      int currentStatus = 2001;
      for( int i = 2; i < argc; i++ )
        {
        currentStatus = RegressionTestImage(argv[1], argv[i], 0, false);
        if( currentStatus < bestBaselineStatus )
          {
          bestBaselineStatus = currentStatus;
          bestBaseline = i;
          }
        if( bestBaselineStatus == 0 )
          {
          break;
          }
        }
      }
    // generate images of our closest match
    if( bestBaselineStatus == 0 )
      {
      RegressionTestImage(argv[1], argv[bestBaseline], 1, false);
      }
    else
      {
      RegressionTestImage(argv[1], argv[bestBaseline], 1, true);
      }
    }
  catch( const itk::ExceptionObject& e )
    {
    std::cerr << "ITK test driver caught an ITK exception:\n";
    std::cerr << e.GetFile() << ":" << e.GetLine() << ":\n"
              << e.GetDescription() << "\n";
    bestBaselineStatus = -1;
    }
  catch( const std::exception& e )
    {
    std::cerr << "ITK test driver caught an exception:\n";
    std::cerr << e.what() << "\n";
    bestBaselineStatus = -1;
    }
  catch( ... )
    {
    std::cerr << "ITK test driver caught an unknown exception!!!\n";
    bestBaselineStatus = -1;
    }
  cout << bestBaselineStatus << endl;
  return bestBaselineStatus;
}

// Regression Testing Code
int RegressionTestImage(const char *testImageFilename, const char *baselineImageFilename,
                        int reportErrors, bool differences)
{
  // Use the factory mechanism to read the test and baseline files and convert them to double
  typedef itk::Image<double, ITK_TEST_DIMENSION_MAX>        ImageType;
  typedef itk::Image<unsigned char, ITK_TEST_DIMENSION_MAX> OutputType;
  typedef itk::Image<unsigned char, 2>                      DiffOutputType;
  typedef itk::ImageFileReader<ImageType>                   ReaderType;

  // Read the baseline file
  ReaderType::Pointer baselineReader = ReaderType::New();
  baselineReader->SetFileName(baselineImageFilename);
  try
    {
    baselineReader->UpdateLargestPossibleRegion();
    }
  catch( itk::ExceptionObject& e )
    {
    std::cerr << "Exception detected while reading " << baselineImageFilename << " : "  << e.GetDescription();
    return 1000;
    }

  // Read the file generated by the test
  ReaderType::Pointer testReader = ReaderType::New();
  testReader->SetFileName(testImageFilename);
  try
    {
    testReader->UpdateLargestPossibleRegion();
    }
  catch( itk::ExceptionObject& e )
    {
    std::cerr << "Exception detected while reading " << testImageFilename << " : "  << e.GetDescription() << std::endl;
    return 1000;
    }

  // The sizes of the baseline and test image must match
  ImageType::SizeType baselineSize;
  baselineSize = baselineReader->GetOutput()->GetLargestPossibleRegion().GetSize();
  ImageType::SizeType testSize;
  testSize = testReader->GetOutput()->GetLargestPossibleRegion().GetSize();

  if( baselineSize != testSize )
    {
    std::cerr << "The size of the Baseline image and Test image do not match!" << std::endl;
    std::cerr << "Baseline image: " << baselineImageFilename
              << " has size " << baselineSize << std::endl;
    std::cerr << "Test image:     " << testImageFilename
              << " has size " << testSize << std::endl;
    return 1;
    }

  // Now compare the two images
  typedef itk::DifferenceImageFilter<ImageType, ImageType> DiffType;
  DiffType::Pointer diff = DiffType::New();
  diff->SetValidInput(baselineReader->GetOutput() );
  diff->SetTestInput(testReader->GetOutput() );
  diff->SetDifferenceThreshold(2.0);
  diff->UpdateLargestPossibleRegion();

  double status = diff->GetTotalDifference();

  if( reportErrors )
    {
    typedef itk::RescaleIntensityImageFilter<ImageType, OutputType> RescaleType;
    typedef itk::ExtractImageFilter<OutputType, DiffOutputType>     ExtractType;
    typedef itk::ImageFileWriter<DiffOutputType>                    WriterType;
    typedef itk::ImageRegion<ITK_TEST_DIMENSION_MAX>                RegionType;
    OutputType::IndexType index; index.Fill(0);
    OutputType::SizeType  size; size.Fill(0);

    RescaleType::Pointer rescale = RescaleType::New();
    rescale->SetOutputMinimum(itk::NumericTraits<unsigned char>::NonpositiveMin() );
    rescale->SetOutputMaximum(itk::NumericTraits<unsigned char>::max() );
    rescale->SetInput(diff->GetOutput() );
    rescale->UpdateLargestPossibleRegion();

    RegionType region;
    region.SetIndex(index);

    size = rescale->GetOutput()->GetLargestPossibleRegion().GetSize();
    for( unsigned int i = 2; i < ITK_TEST_DIMENSION_MAX; i++ )
      {
      size[i] = 0;
      }
    region.SetSize(size);

    ExtractType::Pointer extract = ExtractType::New();
    extract->SetInput(rescale->GetOutput() );
    extract->SetExtractionRegion(region);

    WriterType::Pointer writer = WriterType::New();
    writer->SetInput(extract->GetOutput() );
    if( differences )
      {
      // if there are discrepencies, create an diff image
      std::cout << "<DartMeasurement name=\"ImageError\" type=\"numeric/double\">";
      std::cout << status;
      std::cout <<  "</DartMeasurement>" << std::endl;

      std::ostringstream diffName;
      diffName << testImageFilename << ".diff.png";
      try
        {
        rescale->SetInput(diff->GetOutput() );
        rescale->Update();
        }
      catch( ... )
        {
        std::cerr << "Error during rescale of " << diffName.str() << std::endl;
        }
      writer->SetFileName(diffName.str().c_str() );
      try
        {
        writer->Update();
        }
      catch( ... )
        {
        std::cerr << "Error during write of " << diffName.str() << std::endl;
        }

      std::cout << "<DartMeasurementFile name=\"DifferenceImage\" type=\"image/png\">";
      std::cout << diffName.str();
      std::cout << "</DartMeasurementFile>" << std::endl;
      }
    std::ostringstream baseName;
    baseName << testImageFilename << ".base.png";
    try
      {
      rescale->SetInput(baselineReader->GetOutput() );
      rescale->Update();
      }
    catch( ... )
      {
      std::cerr << "Error during rescale of " << baseName.str() << std::endl;
      }
    try
      {
      writer->SetFileName(baseName.str().c_str() );
      writer->Update();
      }
    catch( ... )
      {
      std::cerr << "Error during write of " << baseName.str() << std::endl;
      }

    std::cout << "<DartMeasurementFile name=\"BaselineImage\" type=\"image/png\">";
    std::cout << baseName.str();
    std::cout << "</DartMeasurementFile>" << std::endl;

    std::ostringstream testName;
    testName << testImageFilename << ".test.png";
    try
      {
      rescale->SetInput(testReader->GetOutput() );
      rescale->Update();
      }
    catch( ... )
      {
      std::cerr << "Error during rescale of " << testName.str()
                << std::endl;
      }
    try
      {
      writer->SetFileName(testName.str().c_str() );
      writer->Update();
      }
    catch( ... )
      {
      std::cerr << "Error during write of " << testName.str() << std::endl;
      }

    std::cout << "<DartMeasurementFile name=\"TestImage\" type=\"image/png\">";
    std::cout << testName.str();
    std::cout << "</DartMeasurementFile>" << std::endl;
    }
  return (status != 0) ? 1 : 0;
}
<commit_msg>COMP:  ITKv4 compatibility<commit_after>#include "itkWin32Header.h"
#include <iostream>
#include <fstream>
#include "itkNumericTraits.h"
#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"
#include "itkExtractImageFilter.h"
#include "itkTestingComparisonImageFilter.h"

using namespace std;

#define ITK_TEST_DIMENSION_MAX 6

int RegressionTestImage(const char *, const char *, int, bool);

int main(int argc, char * *argv)
{
  if( argc < 3 )
    {
    cerr << "Usage:" << endl;
    cerr << "testImage, baselineImage1, [baselineImage2, baselineImage3, ...]" << endl;
    cerr << "Note that if you supply more than one baselineImage, this test will pass if any" << endl;
    cerr << "of them match the testImage" << endl;
    return -1;
    }
  int bestBaselineStatus = 2001;
  int bestBaseline = 2;
  try
    {
    if( argc == 3 )
      {
      bestBaselineStatus = RegressionTestImage(argv[1], argv[2], 0, false);
      }
    else
      {
      int currentStatus = 2001;
      for( int i = 2; i < argc; i++ )
        {
        currentStatus = RegressionTestImage(argv[1], argv[i], 0, false);
        if( currentStatus < bestBaselineStatus )
          {
          bestBaselineStatus = currentStatus;
          bestBaseline = i;
          }
        if( bestBaselineStatus == 0 )
          {
          break;
          }
        }
      }
    // generate images of our closest match
    if( bestBaselineStatus == 0 )
      {
      RegressionTestImage(argv[1], argv[bestBaseline], 1, false);
      }
    else
      {
      RegressionTestImage(argv[1], argv[bestBaseline], 1, true);
      }
    }
  catch( const itk::ExceptionObject& e )
    {
    std::cerr << "ITK test driver caught an ITK exception:\n";
    std::cerr << e.GetFile() << ":" << e.GetLine() << ":\n"
              << e.GetDescription() << "\n";
    bestBaselineStatus = -1;
    }
  catch( const std::exception& e )
    {
    std::cerr << "ITK test driver caught an exception:\n";
    std::cerr << e.what() << "\n";
    bestBaselineStatus = -1;
    }
  catch( ... )
    {
    std::cerr << "ITK test driver caught an unknown exception!!!\n";
    bestBaselineStatus = -1;
    }
  cout << bestBaselineStatus << endl;
  return bestBaselineStatus;
}

// Regression Testing Code
int RegressionTestImage(const char *testImageFilename, const char *baselineImageFilename,
                        int reportErrors, bool differences)
{
  // Use the factory mechanism to read the test and baseline files and convert them to double
  typedef itk::Image<double, ITK_TEST_DIMENSION_MAX>        ImageType;
  typedef itk::Image<unsigned char, ITK_TEST_DIMENSION_MAX> OutputType;
  typedef itk::Image<unsigned char, 2>                      DiffOutputType;
  typedef itk::ImageFileReader<ImageType>                   ReaderType;

  // Read the baseline file
  ReaderType::Pointer baselineReader = ReaderType::New();
  baselineReader->SetFileName(baselineImageFilename);
  try
    {
    baselineReader->UpdateLargestPossibleRegion();
    }
  catch( itk::ExceptionObject& e )
    {
    std::cerr << "Exception detected while reading " << baselineImageFilename << " : "  << e.GetDescription();
    return 1000;
    }

  // Read the file generated by the test
  ReaderType::Pointer testReader = ReaderType::New();
  testReader->SetFileName(testImageFilename);
  try
    {
    testReader->UpdateLargestPossibleRegion();
    }
  catch( itk::ExceptionObject& e )
    {
    std::cerr << "Exception detected while reading " << testImageFilename << " : "  << e.GetDescription() << std::endl;
    return 1000;
    }

  // The sizes of the baseline and test image must match
  ImageType::SizeType baselineSize;
  baselineSize = baselineReader->GetOutput()->GetLargestPossibleRegion().GetSize();
  ImageType::SizeType testSize;
  testSize = testReader->GetOutput()->GetLargestPossibleRegion().GetSize();

  if( baselineSize != testSize )
    {
    std::cerr << "The size of the Baseline image and Test image do not match!" << std::endl;
    std::cerr << "Baseline image: " << baselineImageFilename
              << " has size " << baselineSize << std::endl;
    std::cerr << "Test image:     " << testImageFilename
              << " has size " << testSize << std::endl;
    return 1;
    }

  // Now compare the two images
  typedef itk::Testing::ComparisonImageFilter<ImageType, ImageType> DiffType;
  DiffType::Pointer diff = DiffType::New();
  diff->SetValidInput(baselineReader->GetOutput() );
  diff->SetTestInput(testReader->GetOutput() );
  diff->SetDifferenceThreshold(2.0);
  diff->UpdateLargestPossibleRegion();

  double status = diff->GetTotalDifference();

  if( reportErrors )
    {
    typedef itk::RescaleIntensityImageFilter<ImageType, OutputType> RescaleType;
    typedef itk::ExtractImageFilter<OutputType, DiffOutputType>     ExtractType;
    typedef itk::ImageFileWriter<DiffOutputType>                    WriterType;
    typedef itk::ImageRegion<ITK_TEST_DIMENSION_MAX>                RegionType;
    OutputType::IndexType index; index.Fill(0);
    OutputType::SizeType  size; size.Fill(0);

    RescaleType::Pointer rescale = RescaleType::New();
    rescale->SetOutputMinimum(itk::NumericTraits<unsigned char>::NonpositiveMin() );
    rescale->SetOutputMaximum(itk::NumericTraits<unsigned char>::max() );
    rescale->SetInput(diff->GetOutput() );
    rescale->UpdateLargestPossibleRegion();

    RegionType region;
    region.SetIndex(index);

    size = rescale->GetOutput()->GetLargestPossibleRegion().GetSize();
    for( unsigned int i = 2; i < ITK_TEST_DIMENSION_MAX; i++ )
      {
      size[i] = 0;
      }
    region.SetSize(size);

    ExtractType::Pointer extract = ExtractType::New();
    extract->SetInput(rescale->GetOutput() );
    extract->SetExtractionRegion(region);

    WriterType::Pointer writer = WriterType::New();
    writer->SetInput(extract->GetOutput() );
    if( differences )
      {
      // if there are discrepencies, create an diff image
      std::cout << "<DartMeasurement name=\"ImageError\" type=\"numeric/double\">";
      std::cout << status;
      std::cout <<  "</DartMeasurement>" << std::endl;

      std::ostringstream diffName;
      diffName << testImageFilename << ".diff.png";
      try
        {
        rescale->SetInput(diff->GetOutput() );
        rescale->Update();
        }
      catch( ... )
        {
        std::cerr << "Error during rescale of " << diffName.str() << std::endl;
        }
      writer->SetFileName(diffName.str().c_str() );
      try
        {
        writer->Update();
        }
      catch( ... )
        {
        std::cerr << "Error during write of " << diffName.str() << std::endl;
        }

      std::cout << "<DartMeasurementFile name=\"DifferenceImage\" type=\"image/png\">";
      std::cout << diffName.str();
      std::cout << "</DartMeasurementFile>" << std::endl;
      }
    std::ostringstream baseName;
    baseName << testImageFilename << ".base.png";
    try
      {
      rescale->SetInput(baselineReader->GetOutput() );
      rescale->Update();
      }
    catch( ... )
      {
      std::cerr << "Error during rescale of " << baseName.str() << std::endl;
      }
    try
      {
      writer->SetFileName(baseName.str().c_str() );
      writer->Update();
      }
    catch( ... )
      {
      std::cerr << "Error during write of " << baseName.str() << std::endl;
      }

    std::cout << "<DartMeasurementFile name=\"BaselineImage\" type=\"image/png\">";
    std::cout << baseName.str();
    std::cout << "</DartMeasurementFile>" << std::endl;

    std::ostringstream testName;
    testName << testImageFilename << ".test.png";
    try
      {
      rescale->SetInput(testReader->GetOutput() );
      rescale->Update();
      }
    catch( ... )
      {
      std::cerr << "Error during rescale of " << testName.str()
                << std::endl;
      }
    try
      {
      writer->SetFileName(testName.str().c_str() );
      writer->Update();
      }
    catch( ... )
      {
      std::cerr << "Error during write of " << testName.str() << std::endl;
      }

    std::cout << "<DartMeasurementFile name=\"TestImage\" type=\"image/png\">";
    std::cout << testName.str();
    std::cout << "</DartMeasurementFile>" << std::endl;
    }
  return (status != 0) ? 1 : 0;
}
<|endoftext|>


<commit_before>///
/// @file   cmdoptions.cpp
/// @brief  Parse command-line options for the primecount console
///         (terminal) application.
///
/// Copyright (C) 2015 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include "cmdoptions.hpp"
#include <primecount-internal.hpp>
#include <int128.hpp>

#include <stdint.h>
#include <vector>
#include <string>
#include <sstream>
#include <map>
#include <exception>
#include <cstdlib>
#include <cstddef>

using std::string;
using std::istringstream;

namespace primecount {

void help();
void version();
bool test();

double to_double(const string& s)
{
  istringstream i(s);
  double x;
  if (!(i >> x))
    throw primecount_error("failed to convert \"" + s + "\" to double");
  return x;
}

/// e.g. id = "--threads", value = "4"
struct Option
{
  string id;
  string value;
  template <typename T>
  T getValue() const
  {
    return (T) to_maxint(value);
  }
};

/// Command-line options
std::map<string, OptionValues> optionMap;

void initOptionMap()
{
  optionMap["-a"]                          = OPTION_ALPHA;
  optionMap["--alpha"]                     = OPTION_ALPHA;
  optionMap["-d"]                          = OPTION_DELEGLISE_RIVAT;
  optionMap["--deleglise_rivat"]           = OPTION_DELEGLISE_RIVAT;
  optionMap["--deleglise_rivat1"]          = OPTION_DELEGLISE_RIVAT1;
  optionMap["--deleglise_rivat2"]          = OPTION_DELEGLISE_RIVAT2;
  optionMap["--deleglise_rivat_parallel1"] = OPTION_DELEGLISE_RIVAT_PARALLEL1;
  optionMap["--deleglise_rivat_parallel2"] = OPTION_DELEGLISE_RIVAT_PARALLEL2;
  optionMap["--deleglise_rivat_parallel3"] = OPTION_DELEGLISE_RIVAT_PARALLEL3;
  optionMap["-h"]                          = OPTION_HELP;
  optionMap["--help"]                      = OPTION_HELP;
  optionMap["--legendre"]                  = OPTION_LEGENDRE;
  optionMap["--lehmer"]                    = OPTION_LEHMER;
  optionMap["--lehmer2"]                   = OPTION_LEHMER2;
  optionMap["-l"]                          = OPTION_LMO;
  optionMap["--lmo"]                       = OPTION_LMO;
  optionMap["--lmo1"]                      = OPTION_LMO1;
  optionMap["--lmo2"]                      = OPTION_LMO2;
  optionMap["--lmo3"]                      = OPTION_LMO3;
  optionMap["--lmo4"]                      = OPTION_LMO4;
  optionMap["--lmo5"]                      = OPTION_LMO5;
  optionMap["--lmo_parallel1"]             = OPTION_LMO_PARALLEL1;
  optionMap["--lmo_parallel2"]             = OPTION_LMO_PARALLEL2;
  optionMap["--lmo_parallel3"]             = OPTION_LMO_PARALLEL3;
  optionMap["--Li"]                        = OPTION_LI;
  optionMap["--Li_inverse"]                = OPTION_LIINV;
  optionMap["-m"]                          = OPTION_MEISSEL;
  optionMap["--meissel"]                   = OPTION_MEISSEL;
  optionMap["-n"]                          = OPTION_NTHPRIME;
  optionMap["--nthprime"]                  = OPTION_NTHPRIME;
  optionMap["--number"]                    = OPTION_NUMBER;
  optionMap["--pi"]                        = OPTION_PI;
  optionMap["-p"]                          = OPTION_PRIMESIEVE;
  optionMap["--primesieve"]                = OPTION_PRIMESIEVE;
  optionMap["-s"]                          = OPTION_STATUS;
  optionMap["--status"]                    = OPTION_STATUS;
  optionMap["--test"]                      = OPTION_TEST;
  optionMap["--time"]                      = OPTION_TIME;
  optionMap["-t"]                          = OPTION_THREADS;
  optionMap["--threads"]                   = OPTION_THREADS;
  optionMap["-v"]                          = OPTION_VERSION;
  optionMap["--version"]                   = OPTION_VERSION;
}

/// e.g. "--threads=8" -> { id = "--threads", value = "8" }
Option makeOption(const string& str)
{
  Option option;
  size_t delimiter = string::npos;
  if (optionMap.count(str) == 0)
    delimiter = str.find_first_of("=0123456789");

  if (delimiter == string::npos)
    option.id = str;
  else
  {
    option.id = str.substr(0, delimiter);
    option.value = str.substr(delimiter + (str.at(delimiter) == '=' ? 1 : 0));
  }
  if (option.id.empty() && !option.value.empty())
    option.id = "--number";
  if (optionMap.count(option.id) == 0)
    option.id = "--help";

  return option;
}

PrimeCountOptions parseOptions(int argc, char** argv)
{
  initOptionMap();
  PrimeCountOptions pco;
  std::vector<maxint_t> numbers;

  try
  {
    // iterate over the command-line options
    for (int i = 1; i < argc; i++)
    {
      Option option = makeOption(argv[i]);
      switch (optionMap[option.id])
      {
        case OPTION_ALPHA:   set_alpha(to_double(option.value)); break;
        case OPTION_NUMBER:  numbers.push_back(option.getValue<maxint_t>()); break;
        case OPTION_THREADS: pco.threads = option.getValue<int>(); break;
        case OPTION_HELP:    help(); break;
        case OPTION_STATUS:  set_print_status(true); pco.time = true; break;
        case OPTION_TIME:    pco.time = true; break;
        case OPTION_TEST:    if (test()) exit(0); exit(1);
        case OPTION_VERSION: version(); break;
        default:             pco.option = optionMap[option.id];
      }
    }
  }
  catch (std::exception&)
  {
    help();
  }

  if (numbers.size() == 1)
    pco.x = numbers[0];
  else
    help();

  return pco;
}

} // namespace primecount
<commit_msg>Add more options<commit_after>///
/// @file   cmdoptions.cpp
/// @brief  Parse command-line options for the primecount console
///         (terminal) application.
///
/// Copyright (C) 2015 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include "cmdoptions.hpp"
#include <primecount-internal.hpp>
#include <int128.hpp>

#include <stdint.h>
#include <vector>
#include <string>
#include <sstream>
#include <map>
#include <exception>
#include <cstdlib>
#include <cstddef>

using std::string;
using std::istringstream;

namespace primecount {

void help();
void version();
bool test();

double to_double(const string& s)
{
  istringstream i(s);
  double x;
  if (!(i >> x))
    throw primecount_error("failed to convert \"" + s + "\" to double");
  return x;
}

/// e.g. id = "--threads", value = "4"
struct Option
{
  string id;
  string value;
  template <typename T>
  T getValue() const
  {
    return (T) to_maxint(value);
  }
};

/// Command-line options
std::map<string, OptionValues> optionMap;

void initOptionMap()
{
  optionMap["-a"]                          = OPTION_ALPHA;
  optionMap["--alpha"]                     = OPTION_ALPHA;
  optionMap["-d"]                          = OPTION_DELEGLISE_RIVAT;
  optionMap["--deleglise_rivat"]           = OPTION_DELEGLISE_RIVAT;
  optionMap["--deleglise_rivat1"]          = OPTION_DELEGLISE_RIVAT1;
  optionMap["--deleglise_rivat2"]          = OPTION_DELEGLISE_RIVAT2;
  optionMap["--deleglise_rivat_parallel1"] = OPTION_DELEGLISE_RIVAT_PARALLEL1;
  optionMap["--deleglise_rivat_parallel2"] = OPTION_DELEGLISE_RIVAT_PARALLEL2;
  optionMap["--deleglise_rivat_parallel3"] = OPTION_DELEGLISE_RIVAT_PARALLEL3;
  optionMap["-h"]                          = OPTION_HELP;
  optionMap["--help"]                      = OPTION_HELP;
  optionMap["--legendre"]                  = OPTION_LEGENDRE;
  optionMap["--lehmer"]                    = OPTION_LEHMER;
  optionMap["--lehmer2"]                   = OPTION_LEHMER2;
  optionMap["-l"]                          = OPTION_LMO;
  optionMap["--lmo"]                       = OPTION_LMO;
  optionMap["--lmo1"]                      = OPTION_LMO1;
  optionMap["--lmo2"]                      = OPTION_LMO2;
  optionMap["--lmo3"]                      = OPTION_LMO3;
  optionMap["--lmo4"]                      = OPTION_LMO4;
  optionMap["--lmo5"]                      = OPTION_LMO5;
  optionMap["--lmo_parallel1"]             = OPTION_LMO_PARALLEL1;
  optionMap["--lmo_parallel2"]             = OPTION_LMO_PARALLEL2;
  optionMap["--lmo_parallel3"]             = OPTION_LMO_PARALLEL3;
  optionMap["--Li"]                        = OPTION_LI;
  optionMap["--Li_inverse"]                = OPTION_LIINV;
  optionMap["-m"]                          = OPTION_MEISSEL;
  optionMap["--meissel"]                   = OPTION_MEISSEL;
  optionMap["-n"]                          = OPTION_NTHPRIME;
  optionMap["--nthprime"]                  = OPTION_NTHPRIME;
  optionMap["--number"]                    = OPTION_NUMBER;
  optionMap["--p2"]                        = OPTION_P2;
  optionMap["--pi"]                        = OPTION_PI;
  optionMap["-p"]                          = OPTION_PRIMESIEVE;
  optionMap["--primesieve"]                = OPTION_PRIMESIEVE;
  optionMap["--s1"]                        = OPTION_S1;
  optionMap["--s2_easy"]                   = OPTION_S2_EASY;
  optionMap["--s2_hard"]                   = OPTION_S2_HARD;
  optionMap["--s2_trivial"]                = OPTION_S2_TRIVIAL;
  optionMap["-s"]                          = OPTION_STATUS;
  optionMap["--status"]                    = OPTION_STATUS;
  optionMap["--test"]                      = OPTION_TEST;
  optionMap["--time"]                      = OPTION_TIME;
  optionMap["-t"]                          = OPTION_THREADS;
  optionMap["--threads"]                   = OPTION_THREADS;
  optionMap["-v"]                          = OPTION_VERSION;
  optionMap["--version"]                   = OPTION_VERSION;
}

/// e.g. "--threads=8" -> { id = "--threads", value = "8" }
Option makeOption(const string& str)
{
  Option option;
  size_t delimiter = string::npos;
  if (optionMap.count(str) == 0)
    delimiter = str.find_first_of("=0123456789");

  if (delimiter == string::npos)
    option.id = str;
  else
  {
    option.id = str.substr(0, delimiter);
    option.value = str.substr(delimiter + (str.at(delimiter) == '=' ? 1 : 0));
  }
  if (option.id.empty() && !option.value.empty())
    option.id = "--number";
  if (optionMap.count(option.id) == 0)
    option.id = "--help";

  return option;
}

PrimeCountOptions parseOptions(int argc, char** argv)
{
  initOptionMap();
  PrimeCountOptions pco;
  std::vector<maxint_t> numbers;

  try
  {
    // iterate over the command-line options
    for (int i = 1; i < argc; i++)
    {
      Option option = makeOption(argv[i]);
      switch (optionMap[option.id])
      {
        case OPTION_ALPHA:   set_alpha(to_double(option.value)); break;
        case OPTION_NUMBER:  numbers.push_back(option.getValue<maxint_t>()); break;
        case OPTION_THREADS: pco.threads = option.getValue<int>(); break;
        case OPTION_HELP:    help(); break;
        case OPTION_STATUS:  set_print_status(true); pco.time = true; break;
        case OPTION_TIME:    pco.time = true; break;
        case OPTION_TEST:    if (test()) exit(0); exit(1);
        case OPTION_VERSION: version(); break;
        default:             pco.option = optionMap[option.id];
      }
    }
  }
  catch (std::exception&)
  {
    help();
  }

  if (numbers.size() == 1)
    pco.x = numbers[0];
  else
    help();

  return pco;
}

} // namespace primecount
<|endoftext|>


<commit_before>#include "app/view/arena.h"

#include "core/base/bean_factory.h"
#include "core/util/bean_utils.h"
#include "core/util/holder_util.h"
#include "core/util/log.h"

#include "graphics/base/layer.h"
#include "graphics/base/render_layer.h"

#include "app/base/application_context.h"
#include "app/impl/event_listener/event_listener_list.h"

namespace ark {

Arena::Arena(const sp<ViewGroup>& view, const sp<ResourceLoader>& resourceLoader)
    : _event_listeners(new EventListenerList()), _view_group(view), _resource_loader(resourceLoader)
{
    DCHECK(_view_group, "Arena's renderer delegate must be ViewGroup");
}

Arena::~Arena()
{
    LOGD("");
}

void Arena::addRenderer(const sp<Renderer>& renderer)
{
    DASSERT(_view_group);
    _view_group->addRenderer(renderer);
}

void Arena::render(RenderRequest& renderRequest, const V3& position)
{
    DASSERT(_view_group);
    _view_group->render(renderRequest, position);
    for(const sp<Renderer>& i : _layers.update(renderRequest.timestamp()))
        i->render(renderRequest, position);
}

bool Arena::onEvent(const Event& event)
{
    DASSERT(_view_group);
    return _view_group->onEvent(event, 0.0f, 0.0f, true) || _event_listeners->onEvent(event);
}

void Arena::traverse(const Holder::Visitor& visitor)
{
    HolderUtil::visit(_view_group, visitor);
    for(const auto& i : _layers.items())
        HolderUtil::visit(i._item, visitor);
}

sp<Renderer> Arena::loadRenderer(const String& name, const Scope& args)
{
    const sp<Renderer> renderer = load<Renderer>(name, args);
    addRenderer(renderer);
    return renderer;
}

Box Arena::getReference(const String& id) const
{
    return _resource_loader->refs()->get(id);
}

const sp<ResourceLoader>& Arena::resourceLoader() const
{
    DCHECK(_resource_loader, "Trying to get ResourceLoader on a disposed Arena");
    return _resource_loader;
}

sp<BoxBundle> Arena::refs() const
{
    DCHECK(_resource_loader, "Trying to get ResourceLoader on a disposed Arena");
    return _resource_loader->refs();
}

sp<BoxBundle> Arena::layers() const
{
    DCHECK(_resource_loader, "Trying to get ResourceLoader on a disposed Arena");
    return _resource_loader->layers();
}

sp<BoxBundle> Arena::renderLayers() const
{
    DCHECK(_resource_loader, "Trying to get ResourceLoader on a disposed Arena");
    return _resource_loader->renderLayers();
}

sp<BoxBundle> Arena::packages() const
{
    DCHECK(_resource_loader, "Trying to get ResourceLoader on a disposed Arena");
    return _resource_loader->packages();
}

void Arena::addEventListener(const sp<EventListener>& eventListener, int32_t priority)
{
    _event_listeners->addEventListener(eventListener, priority);
}

void Arena::addLayer(const sp<Renderer>& layer)
{
    _layers.push_back(layer);
}

void Arena::setView(const sp<Renderer>& view)
{
    DCHECK(view.is<ViewGroup>(), "Arena's renderer delegate must be ViewGroup");
    _view_group = view.as<ViewGroup>();
}

const sp<ViewGroup>& Arena::view() const
{
    return _view_group;
}

template<typename T> void addDecoratedLayer(Arena& arena, BeanFactory& factory, const document& manifest, const Scope& args)
{
    const sp<Renderer> layer = factory.build<Renderer>(manifest, args);
    if(layer)
        arena.addLayer(layer);
    else
        arena.addLayer(factory.ensureDecorated<Renderer, T>(manifest, args));
}

Arena::BUILDER::BUILDER(BeanFactory& factory, const document& manifest)
    : _factory(factory), _manifest(manifest), _resource_loader(factory.getBuilder<ResourceLoader>(manifest, "resource-loader")),
      _layout(factory.getBuilder<Layout>(manifest, Constants::Attributes::LAYOUT)),
      _layout_param(factory.ensureBuilder<LayoutParam>(manifest)),
      _background(Documents::getAttribute(manifest, Constants::Attributes::BACKGROUND)),
      _view(Documents::getAttribute(manifest, Constants::Attributes::VIEW))
{
}

sp<Arena> Arena::BUILDER::build(const Scope& args)
{
    const sp<ResourceLoader> r1 = _resource_loader->build(args);
    const sp<ResourceLoader> resourceLoader = r1 ? r1 : sp<ResourceLoader>::make(_factory);
    const sp<Renderer> background = _background.empty() ? nullptr : resourceLoader->load<Renderer>(_background, args);
    const sp<Renderer> view = _view ? resourceLoader->load<Renderer>(_view, args) : nullptr;
    DCHECK(view || background, "Either \"view\" or \"background\" must be specified");
    const sp<Arena> arena = sp<Arena>::make(view ? view : sp<ViewGroup>::make(background, _layout->build(args), nullptr, _layout_param->build(args)).cast<Renderer>(), resourceLoader);

    BeanFactory& factory = resourceLoader->beanFactory();
    for(const document& i : _manifest->children())
    {
        const String& name = i->name();
        if(name == Constants::Attributes::EVENT_LISTENER)
            arena->addEventListener(factory.ensure<EventListener>(i, args));
        else if(name == Constants::Attributes::RENDER_LAYER)
            addDecoratedLayer<RenderLayer>(arena, factory, i, args);
        else if(name == Constants::Attributes::LAYER)
            addDecoratedLayer<Layer>(arena, factory, i, args);
        else
        {
            DWARN(name == Constants::Attributes::RENDERER || name == Constants::Attributes::VIEW, "[Renderer, RenderLayer, Layer, View] expected, \"%s\" found", name.c_str());
            arena->addRenderer(factory.ensure<Renderer>(i, args));
        }
    }
    return arena;
}

}
<commit_msg>Update arena.cpp<commit_after>#include "app/view/arena.h"

#include "core/base/bean_factory.h"
#include "core/util/bean_utils.h"
#include "core/util/holder_util.h"
#include "core/util/log.h"

#include "graphics/base/layer.h"
#include "graphics/base/render_layer.h"

#include "app/base/application_context.h"
#include "app/impl/event_listener/event_listener_list.h"

namespace ark {

Arena::Arena(const sp<ViewGroup>& view, const sp<ResourceLoader>& resourceLoader)
    : _event_listeners(new EventListenerList()), _view_group(view), _resource_loader(resourceLoader)
{
    DCHECK(_view_group, "Arena's renderer delegate must be ViewGroup");
}

Arena::~Arena()
{
    LOGD("");
}

void Arena::addRenderer(const sp<Renderer>& renderer)
{
    DASSERT(_view_group);
    _view_group->addRenderer(renderer);
}

void Arena::render(RenderRequest& renderRequest, const V3& position)
{
    DASSERT(_view_group);
    _view_group->render(renderRequest, position);
    for(const sp<Renderer>& i : _layers.update(renderRequest.timestamp()))
        i->render(renderRequest, position);
}

bool Arena::onEvent(const Event& event)
{
    DASSERT(_view_group);
    return _view_group->onEvent(event, 0.0f, 0.0f, true) || _event_listeners->onEvent(event);
}

void Arena::traverse(const Holder::Visitor& visitor)
{
    HolderUtil::visit(_view_group, visitor);
    for(const auto& i : _layers.items())
        HolderUtil::visit(i._item, visitor);
}

sp<Renderer> Arena::loadRenderer(const String& name, const Scope& args)
{
    const sp<Renderer> renderer = load<Renderer>(name, args);
    addRenderer(renderer);
    return renderer;
}

Box Arena::getReference(const String& id) const
{
    return _resource_loader->refs()->get(id);
}

const sp<ResourceLoader>& Arena::resourceLoader() const
{
    DCHECK(_resource_loader, "Trying to get ResourceLoader on a disposed Arena");
    return _resource_loader;
}

sp<BoxBundle> Arena::refs() const
{
    DCHECK(_resource_loader, "Trying to get ResourceLoader on a disposed Arena");
    return _resource_loader->refs();
}

sp<BoxBundle> Arena::layers() const
{
    DCHECK(_resource_loader, "Trying to get ResourceLoader on a disposed Arena");
    return _resource_loader->layers();
}

sp<BoxBundle> Arena::renderLayers() const
{
    DCHECK(_resource_loader, "Trying to get ResourceLoader on a disposed Arena");
    return _resource_loader->renderLayers();
}

sp<BoxBundle> Arena::packages() const
{
    DCHECK(_resource_loader, "Trying to get ResourceLoader on a disposed Arena");
    return _resource_loader->packages();
}

void Arena::addEventListener(const sp<EventListener>& eventListener, int32_t priority)
{
    _event_listeners->addEventListener(eventListener, priority);
}

void Arena::addLayer(const sp<Renderer>& layer)
{
    _layers.push_back(layer);
}

void Arena::setView(const sp<Renderer>& view)
{
    DCHECK(view.is<ViewGroup>(), "Arena's renderer delegate must be ViewGroup");
    _view_group = view.as<ViewGroup>();
}

const sp<ViewGroup>& Arena::view() const
{
    return _view_group;
}

template<typename T> void addDecoratedLayer(Arena& arena, BeanFactory& factory, const document& manifest, const Scope& args)
{
    const sp<Renderer> layer = factory.build<Renderer>(manifest, args);
    if(layer)
        arena.addLayer(layer);
    else
        arena.addLayer(factory.ensureDecorated<Renderer, T>(manifest, args));
}

Arena::BUILDER::BUILDER(BeanFactory& factory, const document& manifest)
    : _factory(factory), _manifest(manifest), _resource_loader(factory.getBuilder<ResourceLoader>(manifest, "resource-loader")),
      _layout(factory.getBuilder<Layout>(manifest, Constants::Attributes::LAYOUT)),
      _layout_param(factory.ensureBuilder<LayoutParam>(manifest)),
      _background(Documents::getAttribute(manifest, Constants::Attributes::BACKGROUND)),
      _view(Documents::getAttribute(manifest, Constants::Attributes::VIEW))
{
}

sp<Arena> Arena::BUILDER::build(const Scope& args)
{
    const sp<ResourceLoader> r1 = _resource_loader->build(args);
    const sp<ResourceLoader> resourceLoader = r1 ? r1 : sp<ResourceLoader>::make(_factory);
    const sp<Renderer> background = _background.empty() ? nullptr : resourceLoader->load<Renderer>(_background, args);
    const sp<Renderer> view = _view ? resourceLoader->load<Renderer>(_view, args) : nullptr;
    const sp<Arena> arena = sp<Arena>::make(view ? view : sp<ViewGroup>::make(background, _layout->build(args), nullptr, _layout_param->build(args)).cast<Renderer>(), resourceLoader);

    BeanFactory& factory = resourceLoader->beanFactory();
    for(const document& i : _manifest->children())
    {
        const String& name = i->name();
        if(name == Constants::Attributes::EVENT_LISTENER)
            arena->addEventListener(factory.ensure<EventListener>(i, args));
        else if(name == Constants::Attributes::RENDER_LAYER)
            addDecoratedLayer<RenderLayer>(arena, factory, i, args);
        else if(name == Constants::Attributes::LAYER)
            addDecoratedLayer<Layer>(arena, factory, i, args);
        else
        {
            DWARN(name == Constants::Attributes::RENDERER || name == Constants::Attributes::VIEW, "[Renderer, RenderLayer, Layer, View] expected, \"%s\" found", name.c_str());
            arena->addRenderer(factory.ensure<Renderer>(i, args));
        }
    }
    return arena;
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2003-2007 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "arch/x86/faults.hh"

#include "arch/x86/generated/decoder.hh"
#include "arch/x86/insts/static_inst.hh"
#include "arch/x86/mmu.hh"
#include "arch/x86/regs/misc.hh"
#include "base/loader/symtab.hh"
#include "base/trace.hh"
#include "cpu/thread_context.hh"
#include "debug/Faults.hh"
#include "sim/full_system.hh"
#include "sim/process.hh"

namespace gem5
{

namespace X86ISA
{

void
X86FaultBase::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    if (!FullSystem) {
        FaultBase::invoke(tc, inst);
        return;
    }

    PCState pc = tc->pcState().as<PCState>();
    DPRINTF(Faults, "RIP %#x: vector %d: %s\n", pc.pc(), vector, describe());
    using namespace X86ISAInst::rom_labels;
    HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
    MicroPC entry;
    if (m5reg.mode == LongMode) {
        entry = extern_label_longModeInterrupt;
    } else {
        if (m5reg.submode == RealMode)
            entry = extern_label_realModeInterrupt;
        else
            entry = extern_label_legacyModeInterrupt;
    }
    tc->setIntReg(INTREG_MICRO(1), vector);
    tc->setIntReg(INTREG_MICRO(7), pc.pc());
    if (errorCode != (uint64_t)(-1)) {
        if (m5reg.mode == LongMode) {
            entry = extern_label_longModeInterruptWithError;
        } else {
            panic("Legacy mode interrupts with error codes "
                    "aren't implemented.");
        }
        tc->setIntReg(INTREG_MICRO(15), errorCode);
    }
    pc.upc(romMicroPC(entry));
    pc.nupc(romMicroPC(entry) + 1);
    tc->pcState(pc);
}

std::string
X86FaultBase::describe() const
{
    std::stringstream ss;
    ccprintf(ss, "%s", mnemonic());
    if (errorCode != (uint64_t)(-1))
        ccprintf(ss, "(%#x)", errorCode);

    return ss.str();
}

void
X86Trap::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    // This is the same as a fault, but it happens -after- the
    // instruction.
    X86FaultBase::invoke(tc);
}

void
X86Abort::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    panic("Abort exception!");
}

void
InvalidOpcode::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    if (FullSystem) {
        X86Fault::invoke(tc, inst);
    } else {
        auto *xsi = static_cast<X86StaticInst *>(inst.get());
        panic("Unrecognized/invalid instruction executed:\n %s",
                xsi->machInst);
    }
}

void
PageFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    if (FullSystem) {
        // Invalidate any matching TLB entries before handling the page fault.
        tc->getMMUPtr()->demapPage(addr, 0);
        HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
        X86FaultBase::invoke(tc);
        // If something bad happens while trying to enter the page fault
        // handler, I'm pretty sure that's a double fault and then all
        // bets are off. That means it should be safe to update this
        // state now.
        if (m5reg.mode == LongMode)
            tc->setMiscReg(MISCREG_CR2, addr);
        else
            tc->setMiscReg(MISCREG_CR2, (uint32_t)addr);
    } else if (!tc->getProcessPtr()->fixupFault(addr)) {
        PageFaultErrorCode code = errorCode;
        const char *modeStr = "";
        if (code.fetch)
            modeStr = "execute";
        else if (code.write)
            modeStr = "write";
        else
            modeStr = "read";

        // print information about what we are panic'ing on
        if (!inst) {
            panic("Tried to %s unmapped address %#x.", modeStr, addr);
        } else {
            panic("Tried to %s unmapped address %#x.\nPC: %#x, Instr: %s",
                  modeStr, addr, tc->pcState(),
                  inst->disassemble(tc->pcState().instAddr(),
                      &loader::debugSymbolTable));
        }
    }
}

std::string
PageFault::describe() const
{
    std::stringstream ss;
    ccprintf(ss, "%s at %#x", X86FaultBase::describe(), addr);
    return ss.str();
}

void
InitInterrupt::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    DPRINTF(Faults, "Init interrupt.\n");
    // The otherwise unmodified integer registers should be set to 0.
    for (int index = 0; index < NUM_ARCH_INTREGS; index++) {
        tc->setIntReg(index, 0);
    }

    CR0 cr0 = tc->readMiscReg(MISCREG_CR0);
    CR0 newCR0 = 1 << 4;
    newCR0.cd = cr0.cd;
    newCR0.nw = cr0.nw;
    tc->setMiscReg(MISCREG_CR0, newCR0);
    tc->setMiscReg(MISCREG_CR2, 0);
    tc->setMiscReg(MISCREG_CR3, 0);
    tc->setMiscReg(MISCREG_CR4, 0);

    tc->setMiscReg(MISCREG_RFLAGS, 0x0000000000000002ULL);

    tc->setMiscReg(MISCREG_EFER, 0);

    SegAttr dataAttr = 0;
    dataAttr.dpl = 0;
    dataAttr.unusable = 0;
    dataAttr.defaultSize = 0;
    dataAttr.longMode = 0;
    dataAttr.avl = 0;
    dataAttr.granularity = 0;
    dataAttr.present = 1;
    dataAttr.type = 3;
    dataAttr.writable = 1;
    dataAttr.readable = 1;
    dataAttr.expandDown = 0;
    dataAttr.system = 1;

    for (int seg = 0; seg != NUM_SEGMENTREGS; seg++) {
        tc->setMiscReg(MISCREG_SEG_SEL(seg), 0);
        tc->setMiscReg(MISCREG_SEG_BASE(seg), 0);
        tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), 0);
        tc->setMiscReg(MISCREG_SEG_LIMIT(seg), 0xffff);
        tc->setMiscReg(MISCREG_SEG_ATTR(seg), dataAttr);
    }

    SegAttr codeAttr = 0;
    codeAttr.dpl = 0;
    codeAttr.unusable = 0;
    codeAttr.defaultSize = 0;
    codeAttr.longMode = 0;
    codeAttr.avl = 0;
    codeAttr.granularity = 0;
    codeAttr.present = 1;
    codeAttr.type = 10;
    codeAttr.writable = 0;
    codeAttr.readable = 1;
    codeAttr.expandDown = 0;
    codeAttr.system = 1;

    tc->setMiscReg(MISCREG_CS, 0xf000);
    tc->setMiscReg(MISCREG_CS_BASE,
            0x00000000ffff0000ULL);
    tc->setMiscReg(MISCREG_CS_EFF_BASE,
            0x00000000ffff0000ULL);
    // This has the base value pre-added.
    tc->setMiscReg(MISCREG_CS_LIMIT, 0xffffffff);
    tc->setMiscReg(MISCREG_CS_ATTR, codeAttr);

    PCState pc(0x000000000000fff0ULL + tc->readMiscReg(MISCREG_CS_BASE));
    tc->pcState(pc);

    tc->setMiscReg(MISCREG_TSG_BASE, 0);
    tc->setMiscReg(MISCREG_TSG_LIMIT, 0xffff);

    tc->setMiscReg(MISCREG_IDTR_BASE, 0);
    tc->setMiscReg(MISCREG_IDTR_LIMIT, 0xffff);

    SegAttr tslAttr = 0;
    tslAttr.unusable = 1;
    tslAttr.present = 1;
    tslAttr.type = 2; // LDT
    tc->setMiscReg(MISCREG_TSL, 0);
    tc->setMiscReg(MISCREG_TSL_BASE, 0);
    tc->setMiscReg(MISCREG_TSL_LIMIT, 0xffff);
    tc->setMiscReg(MISCREG_TSL_ATTR, tslAttr);

    SegAttr trAttr = 0;
    trAttr.unusable = 0;
    trAttr.present = 1;
    trAttr.type = 3; // Busy 16-bit TSS
    tc->setMiscReg(MISCREG_TR, 0);
    tc->setMiscReg(MISCREG_TR_BASE, 0);
    tc->setMiscReg(MISCREG_TR_LIMIT, 0xffff);
    tc->setMiscReg(MISCREG_TR_ATTR, trAttr);

    // This value should be the family/model/stepping of the processor.
    // (page 418). It should be consistent with the value from CPUID, but
    // the actual value probably doesn't matter much.
    tc->setIntReg(INTREG_RDX, 0);

    tc->setMiscReg(MISCREG_DR0, 0);
    tc->setMiscReg(MISCREG_DR1, 0);
    tc->setMiscReg(MISCREG_DR2, 0);
    tc->setMiscReg(MISCREG_DR3, 0);

    tc->setMiscReg(MISCREG_DR6, 0x00000000ffff0ff0ULL);
    tc->setMiscReg(MISCREG_DR7, 0x0000000000000400ULL);

    tc->setMiscReg(MISCREG_MXCSR, 0x1f80);

    // Flag all elements on the x87 stack as empty.
    tc->setMiscReg(MISCREG_FTW, 0xFFFF);

    // Update the handy M5 Reg.
    tc->setMiscReg(MISCREG_M5_REG, 0);
    MicroPC entry = X86ISAInst::rom_labels::extern_label_initIntHalt;
    pc.upc(romMicroPC(entry));
    pc.nupc(romMicroPC(entry) + 1);
    tc->pcState(pc);
}

void
StartupInterrupt::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    DPRINTF(Faults, "Startup interrupt with vector %#x.\n", vector);
    HandyM5Reg m5Reg = tc->readMiscReg(MISCREG_M5_REG);
    if (m5Reg.mode != LegacyMode || m5Reg.submode != RealMode) {
        panic("Startup IPI recived outside of real mode. "
                "Don't know what to do. %d, %d", m5Reg.mode, m5Reg.submode);
    }

    tc->setMiscReg(MISCREG_CS, vector << 8);
    tc->setMiscReg(MISCREG_CS_BASE, vector << 12);
    tc->setMiscReg(MISCREG_CS_EFF_BASE, vector << 12);
    // This has the base value pre-added.
    tc->setMiscReg(MISCREG_CS_LIMIT, 0xffff);

    tc->pcState(tc->readMiscReg(MISCREG_CS_BASE));
}

} // namespace X86ISA
} // namespace gem5
<commit_msg>arch-x86: Subtract the base from the PC when entering faults.<commit_after>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2003-2007 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "arch/x86/faults.hh"

#include "arch/x86/generated/decoder.hh"
#include "arch/x86/insts/static_inst.hh"
#include "arch/x86/mmu.hh"
#include "arch/x86/regs/misc.hh"
#include "base/loader/symtab.hh"
#include "base/trace.hh"
#include "cpu/thread_context.hh"
#include "debug/Faults.hh"
#include "sim/full_system.hh"
#include "sim/process.hh"

namespace gem5
{

namespace X86ISA
{

void
X86FaultBase::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    if (!FullSystem) {
        FaultBase::invoke(tc, inst);
        return;
    }

    PCState pc = tc->pcState().as<PCState>();
    DPRINTF(Faults, "RIP %#x: vector %d: %s\n", pc.pc(), vector, describe());
    using namespace X86ISAInst::rom_labels;
    HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
    MicroPC entry;
    if (m5reg.mode == LongMode) {
        entry = extern_label_longModeInterrupt;
    } else {
        if (m5reg.submode == RealMode)
            entry = extern_label_realModeInterrupt;
        else
            entry = extern_label_legacyModeInterrupt;
    }
    tc->setIntReg(INTREG_MICRO(1), vector);
    Addr cs_base = tc->readMiscRegNoEffect(MISCREG_CS_EFF_BASE);
    tc->setIntReg(INTREG_MICRO(7), pc.pc() - cs_base);
    if (errorCode != (uint64_t)(-1)) {
        if (m5reg.mode == LongMode) {
            entry = extern_label_longModeInterruptWithError;
        } else {
            panic("Legacy mode interrupts with error codes "
                    "aren't implemented.");
        }
        tc->setIntReg(INTREG_MICRO(15), errorCode);
    }
    pc.upc(romMicroPC(entry));
    pc.nupc(romMicroPC(entry) + 1);
    tc->pcState(pc);
}

std::string
X86FaultBase::describe() const
{
    std::stringstream ss;
    ccprintf(ss, "%s", mnemonic());
    if (errorCode != (uint64_t)(-1))
        ccprintf(ss, "(%#x)", errorCode);

    return ss.str();
}

void
X86Trap::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    // This is the same as a fault, but it happens -after- the
    // instruction.
    X86FaultBase::invoke(tc);
}

void
X86Abort::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    panic("Abort exception!");
}

void
InvalidOpcode::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    if (FullSystem) {
        X86Fault::invoke(tc, inst);
    } else {
        auto *xsi = static_cast<X86StaticInst *>(inst.get());
        panic("Unrecognized/invalid instruction executed:\n %s",
                xsi->machInst);
    }
}

void
PageFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    if (FullSystem) {
        // Invalidate any matching TLB entries before handling the page fault.
        tc->getMMUPtr()->demapPage(addr, 0);
        HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
        X86FaultBase::invoke(tc);
        // If something bad happens while trying to enter the page fault
        // handler, I'm pretty sure that's a double fault and then all
        // bets are off. That means it should be safe to update this
        // state now.
        if (m5reg.mode == LongMode)
            tc->setMiscReg(MISCREG_CR2, addr);
        else
            tc->setMiscReg(MISCREG_CR2, (uint32_t)addr);
    } else if (!tc->getProcessPtr()->fixupFault(addr)) {
        PageFaultErrorCode code = errorCode;
        const char *modeStr = "";
        if (code.fetch)
            modeStr = "execute";
        else if (code.write)
            modeStr = "write";
        else
            modeStr = "read";

        // print information about what we are panic'ing on
        if (!inst) {
            panic("Tried to %s unmapped address %#x.", modeStr, addr);
        } else {
            panic("Tried to %s unmapped address %#x.\nPC: %#x, Instr: %s",
                  modeStr, addr, tc->pcState(),
                  inst->disassemble(tc->pcState().instAddr(),
                      &loader::debugSymbolTable));
        }
    }
}

std::string
PageFault::describe() const
{
    std::stringstream ss;
    ccprintf(ss, "%s at %#x", X86FaultBase::describe(), addr);
    return ss.str();
}

void
InitInterrupt::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    DPRINTF(Faults, "Init interrupt.\n");
    // The otherwise unmodified integer registers should be set to 0.
    for (int index = 0; index < NUM_ARCH_INTREGS; index++) {
        tc->setIntReg(index, 0);
    }

    CR0 cr0 = tc->readMiscReg(MISCREG_CR0);
    CR0 newCR0 = 1 << 4;
    newCR0.cd = cr0.cd;
    newCR0.nw = cr0.nw;
    tc->setMiscReg(MISCREG_CR0, newCR0);
    tc->setMiscReg(MISCREG_CR2, 0);
    tc->setMiscReg(MISCREG_CR3, 0);
    tc->setMiscReg(MISCREG_CR4, 0);

    tc->setMiscReg(MISCREG_RFLAGS, 0x0000000000000002ULL);

    tc->setMiscReg(MISCREG_EFER, 0);

    SegAttr dataAttr = 0;
    dataAttr.dpl = 0;
    dataAttr.unusable = 0;
    dataAttr.defaultSize = 0;
    dataAttr.longMode = 0;
    dataAttr.avl = 0;
    dataAttr.granularity = 0;
    dataAttr.present = 1;
    dataAttr.type = 3;
    dataAttr.writable = 1;
    dataAttr.readable = 1;
    dataAttr.expandDown = 0;
    dataAttr.system = 1;

    for (int seg = 0; seg != NUM_SEGMENTREGS; seg++) {
        tc->setMiscReg(MISCREG_SEG_SEL(seg), 0);
        tc->setMiscReg(MISCREG_SEG_BASE(seg), 0);
        tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), 0);
        tc->setMiscReg(MISCREG_SEG_LIMIT(seg), 0xffff);
        tc->setMiscReg(MISCREG_SEG_ATTR(seg), dataAttr);
    }

    SegAttr codeAttr = 0;
    codeAttr.dpl = 0;
    codeAttr.unusable = 0;
    codeAttr.defaultSize = 0;
    codeAttr.longMode = 0;
    codeAttr.avl = 0;
    codeAttr.granularity = 0;
    codeAttr.present = 1;
    codeAttr.type = 10;
    codeAttr.writable = 0;
    codeAttr.readable = 1;
    codeAttr.expandDown = 0;
    codeAttr.system = 1;

    tc->setMiscReg(MISCREG_CS, 0xf000);
    tc->setMiscReg(MISCREG_CS_BASE,
            0x00000000ffff0000ULL);
    tc->setMiscReg(MISCREG_CS_EFF_BASE,
            0x00000000ffff0000ULL);
    // This has the base value pre-added.
    tc->setMiscReg(MISCREG_CS_LIMIT, 0xffffffff);
    tc->setMiscReg(MISCREG_CS_ATTR, codeAttr);

    PCState pc(0x000000000000fff0ULL + tc->readMiscReg(MISCREG_CS_BASE));
    tc->pcState(pc);

    tc->setMiscReg(MISCREG_TSG_BASE, 0);
    tc->setMiscReg(MISCREG_TSG_LIMIT, 0xffff);

    tc->setMiscReg(MISCREG_IDTR_BASE, 0);
    tc->setMiscReg(MISCREG_IDTR_LIMIT, 0xffff);

    SegAttr tslAttr = 0;
    tslAttr.unusable = 1;
    tslAttr.present = 1;
    tslAttr.type = 2; // LDT
    tc->setMiscReg(MISCREG_TSL, 0);
    tc->setMiscReg(MISCREG_TSL_BASE, 0);
    tc->setMiscReg(MISCREG_TSL_LIMIT, 0xffff);
    tc->setMiscReg(MISCREG_TSL_ATTR, tslAttr);

    SegAttr trAttr = 0;
    trAttr.unusable = 0;
    trAttr.present = 1;
    trAttr.type = 3; // Busy 16-bit TSS
    tc->setMiscReg(MISCREG_TR, 0);
    tc->setMiscReg(MISCREG_TR_BASE, 0);
    tc->setMiscReg(MISCREG_TR_LIMIT, 0xffff);
    tc->setMiscReg(MISCREG_TR_ATTR, trAttr);

    // This value should be the family/model/stepping of the processor.
    // (page 418). It should be consistent with the value from CPUID, but
    // the actual value probably doesn't matter much.
    tc->setIntReg(INTREG_RDX, 0);

    tc->setMiscReg(MISCREG_DR0, 0);
    tc->setMiscReg(MISCREG_DR1, 0);
    tc->setMiscReg(MISCREG_DR2, 0);
    tc->setMiscReg(MISCREG_DR3, 0);

    tc->setMiscReg(MISCREG_DR6, 0x00000000ffff0ff0ULL);
    tc->setMiscReg(MISCREG_DR7, 0x0000000000000400ULL);

    tc->setMiscReg(MISCREG_MXCSR, 0x1f80);

    // Flag all elements on the x87 stack as empty.
    tc->setMiscReg(MISCREG_FTW, 0xFFFF);

    // Update the handy M5 Reg.
    tc->setMiscReg(MISCREG_M5_REG, 0);
    MicroPC entry = X86ISAInst::rom_labels::extern_label_initIntHalt;
    pc.upc(romMicroPC(entry));
    pc.nupc(romMicroPC(entry) + 1);
    tc->pcState(pc);
}

void
StartupInterrupt::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
    DPRINTF(Faults, "Startup interrupt with vector %#x.\n", vector);
    HandyM5Reg m5Reg = tc->readMiscReg(MISCREG_M5_REG);
    if (m5Reg.mode != LegacyMode || m5Reg.submode != RealMode) {
        panic("Startup IPI recived outside of real mode. "
                "Don't know what to do. %d, %d", m5Reg.mode, m5Reg.submode);
    }

    tc->setMiscReg(MISCREG_CS, vector << 8);
    tc->setMiscReg(MISCREG_CS_BASE, vector << 12);
    tc->setMiscReg(MISCREG_CS_EFF_BASE, vector << 12);
    // This has the base value pre-added.
    tc->setMiscReg(MISCREG_CS_LIMIT, 0xffff);

    tc->pcState(tc->readMiscReg(MISCREG_CS_BASE));
}

} // namespace X86ISA
} // namespace gem5
<|endoftext|>