<commit_before>#include "tools/cabana/settings.h"

#include <QDialogButtonBox>
#include <QFormLayout>
#include <QSettings>

// Settings
Settings settings;

Settings::Settings() {
  load();
}

void Settings::save() {
  QSettings s("settings", QSettings::IniFormat);
  s.setValue("fps", fps);
  s.setValue("log_size", can_msg_log_size);
  s.setValue("cached_segment", cached_segment_limit);
  s.setValue("chart_height", chart_height);
  s.setValue("chart_theme", chart_theme);
  s.setValue("max_chart_x_range", max_chart_x_range);
  emit changed();
}

void Settings::load() {
  QSettings s("settings", QSettings::IniFormat);
  fps = s.value("fps", 10).toInt();
  can_msg_log_size = s.value("log_size", 100).toInt();
  cached_segment_limit = s.value("cached_segment", 3).toInt();
  chart_height = s.value("chart_height", 200).toInt();
  chart_theme = s.value("chart_theme", 0).toInt();
  max_chart_x_range = s.value("max_chart_x_range", 3 * 60).toInt();
}

// SettingsDlg

SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) {
  setWindowTitle(tr("Settings"));
  QVBoxLayout *main_layout = new QVBoxLayout(this);
  QFormLayout *form_layout = new QFormLayout();

  fps = new QSpinBox(this);
  fps->setRange(10, 100);
  fps->setSingleStep(10);
  fps->setValue(settings.fps);
  form_layout->addRow("FPS", fps);

  log_size = new QSpinBox(this);
  log_size->setRange(50, 500);
  log_size->setSingleStep(10);
  log_size->setValue(settings.can_msg_log_size);
  form_layout->addRow(tr("Signal history log size"), log_size);

  cached_segment = new QSpinBox(this);
  cached_segment->setRange(3, 60);
  cached_segment->setSingleStep(1);
  cached_segment->setValue(settings.cached_segment_limit);
  form_layout->addRow(tr("Cached segments limit(minute)"), cached_segment);

  max_chart_x_range = new QSpinBox(this);
  max_chart_x_range->setRange(1, 60);
  max_chart_x_range->setSingleStep(1);
  max_chart_x_range->setValue(settings.max_chart_x_range / 60);
  form_layout->addRow(tr("Chart's max X-axis range(minute)"), max_chart_x_range);

  chart_height = new QSpinBox(this);
  chart_height->setRange(100, 500);
  chart_height->setSingleStep(10);
  chart_height->setValue(settings.chart_height);
  form_layout->addRow(tr("Chart's height"), chart_height);

  chart_theme = new QComboBox();
  chart_theme->addItems({"Light", "Dark"});
  chart_theme->setCurrentIndex(settings.chart_theme == 1 ? 1 : 0);
  form_layout->addRow(tr("Chart theme"), chart_theme);

  main_layout->addLayout(form_layout);

  auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
  main_layout->addWidget(buttonBox);

  setFixedWidth(360);
  connect(buttonBox, &QDialogButtonBox::accepted, this, &SettingsDlg::save);
  connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}

void SettingsDlg::save() {
  settings.fps = fps->value();
  settings.can_msg_log_size = log_size->value();
  settings.cached_segment_limit = cached_segment->value();
  settings.chart_height = chart_height->value();
  settings.chart_theme = chart_theme->currentIndex();
  settings.max_chart_x_range = max_chart_x_range->value() * 60;
  settings.save();
  accept();
}
<commit_msg>cabana: fix settings titles<commit_after>#include "tools/cabana/settings.h"

#include <QDialogButtonBox>
#include <QFormLayout>
#include <QSettings>

// Settings
Settings settings;

Settings::Settings() {
  load();
}

void Settings::save() {
  QSettings s("settings", QSettings::IniFormat);
  s.setValue("fps", fps);
  s.setValue("log_size", can_msg_log_size);
  s.setValue("cached_segment", cached_segment_limit);
  s.setValue("chart_height", chart_height);
  s.setValue("chart_theme", chart_theme);
  s.setValue("max_chart_x_range", max_chart_x_range);
  emit changed();
}

void Settings::load() {
  QSettings s("settings", QSettings::IniFormat);
  fps = s.value("fps", 10).toInt();
  can_msg_log_size = s.value("log_size", 100).toInt();
  cached_segment_limit = s.value("cached_segment", 3).toInt();
  chart_height = s.value("chart_height", 200).toInt();
  chart_theme = s.value("chart_theme", 0).toInt();
  max_chart_x_range = s.value("max_chart_x_range", 3 * 60).toInt();
}

// SettingsDlg

SettingsDlg::SettingsDlg(QWidget *parent) : QDialog(parent) {
  setWindowTitle(tr("Settings"));
  QVBoxLayout *main_layout = new QVBoxLayout(this);
  QFormLayout *form_layout = new QFormLayout();

  fps = new QSpinBox(this);
  fps->setRange(10, 100);
  fps->setSingleStep(10);
  fps->setValue(settings.fps);
  form_layout->addRow("FPS", fps);

  log_size = new QSpinBox(this);
  log_size->setRange(50, 500);
  log_size->setSingleStep(10);
  log_size->setValue(settings.can_msg_log_size);
  form_layout->addRow(tr("Signal history log size"), log_size);

  cached_segment = new QSpinBox(this);
  cached_segment->setRange(3, 60);
  cached_segment->setSingleStep(1);
  cached_segment->setValue(settings.cached_segment_limit);
  form_layout->addRow(tr("Cached segments limit"), cached_segment);

  max_chart_x_range = new QSpinBox(this);
  max_chart_x_range->setRange(1, 60);
  max_chart_x_range->setSingleStep(1);
  max_chart_x_range->setValue(settings.max_chart_x_range / 60);
  form_layout->addRow(tr("Chart range (minutes)"), max_chart_x_range);

  chart_height = new QSpinBox(this);
  chart_height->setRange(100, 500);
  chart_height->setSingleStep(10);
  chart_height->setValue(settings.chart_height);
  form_layout->addRow(tr("Chart height"), chart_height);

  chart_theme = new QComboBox();
  chart_theme->addItems({"Light", "Dark"});
  chart_theme->setCurrentIndex(settings.chart_theme == 1 ? 1 : 0);
  form_layout->addRow(tr("Chart theme"), chart_theme);

  main_layout->addLayout(form_layout);

  auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
  main_layout->addWidget(buttonBox);

  setFixedWidth(360);
  connect(buttonBox, &QDialogButtonBox::accepted, this, &SettingsDlg::save);
  connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}

void SettingsDlg::save() {
  settings.fps = fps->value();
  settings.can_msg_log_size = log_size->value();
  settings.cached_segment_limit = cached_segment->value();
  settings.chart_height = chart_height->value();
  settings.chart_theme = chart_theme->currentIndex();
  settings.max_chart_x_range = max_chart_x_range->value() * 60;
  settings.save();
  accept();
}
<|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

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

#include <mitkDICOMRTMimeTypes.h>

#include <mitkIOMimeTypes.h>

#include <mitkDICOMDCMTKTagScanner.h>
#include <mitkDICOMTagPath.h>
#include <mitkDICOMFileReaderSelector.h>
#include <mitkDICOMFileReader.h>

#include <itksys/SystemTools.hxx>

namespace mitk
{

std::array<std::unique_ptr<CustomMimeType>, 3> DICOMRTMimeTypes::Get()
{
  return {
    std::make_unique<RTDoseMimeType>(),
    std::make_unique<RTPlanMimeType>(),
    std::make_unique<RTStructMimeType>()
  };
}

// Mime Types

DICOMRTMimeTypes::RTDoseMimeType::RTDoseMimeType()
  : CustomMimeType(DICOMRT_DOSE_MIMETYPE_NAME())
{
  std::string category = "DICOMRT";
  this->SetCategory(category);
  this->SetComment("RTDose");

  this->AddExtension("dcm");
}

bool DICOMRTMimeTypes::RTDoseMimeType::AppliesTo(const std::string &path) const
{
  bool canRead( CustomMimeType::AppliesTo(path) );

  if (!canRead)
  {
    return false;
  }

  auto modality = GetModality(path);
  if (modality == "RTDOSE")
  {
    return canReadByDicomFileReader(path);
  }

  return false;
}

std::string DICOMRTMimeTypes::GetModality(const std::string & path)
{
  const auto modalityTagPath = DICOMTagPath(0x0008, 0x0060);

  mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New();
  scanner->SetInputFiles({ path });
  scanner->AddTagPaths({ modalityTagPath });
  scanner->Scan();

  mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList();
  std::string modality = "";
  if (frames.empty())
    return modality;
  auto findings = frames.front()->GetTagValueAsString(modalityTagPath);

  modality = findings.front().value;
  return modality;
}

bool DICOMRTMimeTypes::canReadByDicomFileReader(const std::string & filename)
{
  mitk::DICOMFileReaderSelector::Pointer selector = mitk::DICOMFileReaderSelector::New();
  selector->LoadBuiltIn3DConfigs();
  selector->SetInputFiles({ filename });

  mitk::DICOMFileReader::Pointer reader = selector->GetFirstReaderWithMinimumNumberOfOutputImages();

  return reader.IsNotNull();
}

DICOMRTMimeTypes::RTDoseMimeType* DICOMRTMimeTypes::RTDoseMimeType::Clone() const
{
  return new RTDoseMimeType(*this);
}

DICOMRTMimeTypes::RTStructMimeType::RTStructMimeType()
  : CustomMimeType(DICOMRT_STRUCT_MIMETYPE_NAME())
{
  std::string category = "DICOMRT";
  this->SetCategory(category);
  this->SetComment("RTStruct");

  this->AddExtension("dcm");
}

bool DICOMRTMimeTypes::RTStructMimeType::AppliesTo(const std::string &path) const
{
  bool canRead(CustomMimeType::AppliesTo(path));

  if (!canRead) {
    return false;
  }

  auto modality = GetModality(path);
  if (modality == "RTSTRUCT") {
    return true;
  }

  return false;
}

DICOMRTMimeTypes::RTStructMimeType* DICOMRTMimeTypes::RTStructMimeType::Clone() const
{
  return new RTStructMimeType(*this);
}

DICOMRTMimeTypes::RTPlanMimeType::RTPlanMimeType()
  : CustomMimeType(DICOMRT_PLAN_MIMETYPE_NAME())
{
  std::string category = "DICOMRT";
  this->SetCategory(category);
  this->SetComment("RTPLAN");

  this->AddExtension("dcm");
}

bool DICOMRTMimeTypes::RTPlanMimeType::AppliesTo(const std::string &path) const
{
  bool canRead(CustomMimeType::AppliesTo(path));

  if (!canRead) {
    return false;
  }

  auto modality = GetModality(path);
  if (modality == "RTPLAN") {
    return true;
  }

  return false;
}

DICOMRTMimeTypes::RTPlanMimeType* DICOMRTMimeTypes::RTPlanMimeType::Clone() const
{
  return new RTPlanMimeType(*this);
}

DICOMRTMimeTypes::RTDoseMimeType DICOMRTMimeTypes::DICOMRT_DOSE_MIMETYPE()
{
  return RTDoseMimeType();
}

DICOMRTMimeTypes::RTStructMimeType DICOMRTMimeTypes::DICOMRT_STRUCT_MIMETYPE()
{
  return RTStructMimeType();
}

DICOMRTMimeTypes::RTPlanMimeType DICOMRTMimeTypes::DICOMRT_PLAN_MIMETYPE()
{
  return RTPlanMimeType();
}

// Names
std::string DICOMRTMimeTypes::DICOMRT_DOSE_MIMETYPE_NAME()
{
  return IOMimeTypes::DEFAULT_BASE_NAME() + ".dicomrt.dose";
}

std::string DICOMRTMimeTypes::DICOMRT_STRUCT_MIMETYPE_NAME()
{
  return IOMimeTypes::DEFAULT_BASE_NAME() + ".dicomrt.struct";
}

std::string DICOMRTMimeTypes::DICOMRT_PLAN_MIMETYPE_NAME()
{
  return IOMimeTypes::DEFAULT_BASE_NAME() + ".dicomrt.plan";
}

// Descriptions

std::string DICOMRTMimeTypes::DICOMRT_DOSE_MIMETYPE_DESCRIPTION()
{
  return "RTDOSE reader";
}

std::string DICOMRTMimeTypes::DICOMRT_STRUCT_MIMETYPE_DESCRIPTION()
{
  return "RTSTRUCT reader";
}

std::string DICOMRTMimeTypes::DICOMRT_PLAN_MIMETYPE_DESCRIPTION()
{
  return "RTPLAN reader";
}

}
<commit_msg>Added a check for file existance to prevent tag scanning.<commit_after>/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

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

#include <mitkDICOMRTMimeTypes.h>

#include <mitkIOMimeTypes.h>

#include <mitkDICOMDCMTKTagScanner.h>
#include <mitkDICOMTagPath.h>
#include <mitkDICOMFileReaderSelector.h>
#include <mitkDICOMFileReader.h>

#include <itksys/SystemTools.hxx>

namespace mitk
{

std::array<std::unique_ptr<CustomMimeType>, 3> DICOMRTMimeTypes::Get()
{
  return {
    std::make_unique<RTDoseMimeType>(),
    std::make_unique<RTPlanMimeType>(),
    std::make_unique<RTStructMimeType>()
  };
}

// Mime Types

DICOMRTMimeTypes::RTDoseMimeType::RTDoseMimeType()
  : CustomMimeType(DICOMRT_DOSE_MIMETYPE_NAME())
{
  std::string category = "DICOMRT";
  this->SetCategory(category);
  this->SetComment("RTDose");

  this->AddExtension("dcm");
}

bool DICOMRTMimeTypes::RTDoseMimeType::AppliesTo(const std::string &path) const
{
  bool canRead( CustomMimeType::AppliesTo(path) );

  if (!canRead)
  {
    return false;
  }

  // fix for bug 18572
  // Currently this function is called for writing as well as reading, in that case
  // the image information can of course not be parsed or further identifyed.
  //so as a work arround we just return the current canRead if the file does not exist.
  if (!itksys::SystemTools::FileExists(path.c_str()))
  {
    return canRead;
  }
  // end fix for bug 18572

  auto modality = GetModality(path);
  if (modality == "RTDOSE")
  {
    return canReadByDicomFileReader(path);
  }

  return false;
}

std::string DICOMRTMimeTypes::GetModality(const std::string & path)
{
  const auto modalityTagPath = DICOMTagPath(0x0008, 0x0060);

  mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New();
  scanner->SetInputFiles({ path });
  scanner->AddTagPaths({ modalityTagPath });
  scanner->Scan();

  mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList();
  std::string modality = "";
  if (frames.empty())
    return modality;
  auto findings = frames.front()->GetTagValueAsString(modalityTagPath);

  modality = findings.front().value;
  return modality;
}

bool DICOMRTMimeTypes::canReadByDicomFileReader(const std::string & filename)
{
  mitk::DICOMFileReaderSelector::Pointer selector = mitk::DICOMFileReaderSelector::New();
  selector->LoadBuiltIn3DConfigs();
  selector->SetInputFiles({ filename });

  mitk::DICOMFileReader::Pointer reader = selector->GetFirstReaderWithMinimumNumberOfOutputImages();

  return reader.IsNotNull();
}

DICOMRTMimeTypes::RTDoseMimeType* DICOMRTMimeTypes::RTDoseMimeType::Clone() const
{
  return new RTDoseMimeType(*this);
}

DICOMRTMimeTypes::RTStructMimeType::RTStructMimeType()
  : CustomMimeType(DICOMRT_STRUCT_MIMETYPE_NAME())
{
  std::string category = "DICOMRT";
  this->SetCategory(category);
  this->SetComment("RTStruct");

  this->AddExtension("dcm");
}

bool DICOMRTMimeTypes::RTStructMimeType::AppliesTo(const std::string &path) const
{
  bool canRead(CustomMimeType::AppliesTo(path));

  if (!canRead) {
    return false;
  }

  // fix for bug 18572
  // Currently this function is called for writing as well as reading, in that case
  // the image information can of course not be parsed or further identifyed.
  //so as a work arround we just return the current canRead if the file does not exist.
  if (!itksys::SystemTools::FileExists(path.c_str()))
  {
    return canRead;
  }
  // end fix for bug 18572

  auto modality = GetModality(path);
  if (modality == "RTSTRUCT") {
    return true;
  }

  return false;
}

DICOMRTMimeTypes::RTStructMimeType* DICOMRTMimeTypes::RTStructMimeType::Clone() const
{
  return new RTStructMimeType(*this);
}

DICOMRTMimeTypes::RTPlanMimeType::RTPlanMimeType()
  : CustomMimeType(DICOMRT_PLAN_MIMETYPE_NAME())
{
  std::string category = "DICOMRT";
  this->SetCategory(category);
  this->SetComment("RTPLAN");

  this->AddExtension("dcm");
}

bool DICOMRTMimeTypes::RTPlanMimeType::AppliesTo(const std::string &path) const
{
  bool canRead(CustomMimeType::AppliesTo(path));

  if (!canRead) {
    return false;
  }

  // fix for bug 18572
  // Currently this function is called for writing as well as reading, in that case
  // the image information can of course not be parsed or further identifyed.
  //so as a work arround we just return the current canRead if the file does not exist.
  if (!itksys::SystemTools::FileExists(path.c_str()))
  {
    return canRead;
  }
  // end fix for bug 18572

  auto modality = GetModality(path);
  if (modality == "RTPLAN") {
    return true;
  }

  return false;
}

DICOMRTMimeTypes::RTPlanMimeType* DICOMRTMimeTypes::RTPlanMimeType::Clone() const
{
  return new RTPlanMimeType(*this);
}

DICOMRTMimeTypes::RTDoseMimeType DICOMRTMimeTypes::DICOMRT_DOSE_MIMETYPE()
{
  return RTDoseMimeType();
}

DICOMRTMimeTypes::RTStructMimeType DICOMRTMimeTypes::DICOMRT_STRUCT_MIMETYPE()
{
  return RTStructMimeType();
}

DICOMRTMimeTypes::RTPlanMimeType DICOMRTMimeTypes::DICOMRT_PLAN_MIMETYPE()
{
  return RTPlanMimeType();
}

// Names
std::string DICOMRTMimeTypes::DICOMRT_DOSE_MIMETYPE_NAME()
{
  return IOMimeTypes::DEFAULT_BASE_NAME() + ".dicomrt.dose";
}

std::string DICOMRTMimeTypes::DICOMRT_STRUCT_MIMETYPE_NAME()
{
  return IOMimeTypes::DEFAULT_BASE_NAME() + ".dicomrt.struct";
}

std::string DICOMRTMimeTypes::DICOMRT_PLAN_MIMETYPE_NAME()
{
  return IOMimeTypes::DEFAULT_BASE_NAME() + ".dicomrt.plan";
}

// Descriptions

std::string DICOMRTMimeTypes::DICOMRT_DOSE_MIMETYPE_DESCRIPTION()
{
  return "RTDOSE reader";
}

std::string DICOMRTMimeTypes::DICOMRT_STRUCT_MIMETYPE_DESCRIPTION()
{
  return "RTSTRUCT reader";
}

std::string DICOMRTMimeTypes::DICOMRT_PLAN_MIMETYPE_DESCRIPTION()
{
  return "RTPLAN reader";
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/table.h"

#include <ctype.h>
#include <string.h>

#include "perfetto/base/logging.h"

namespace perfetto {
namespace trace_processor {

namespace {

struct TableDescriptor {
  Table::Factory factory;
  const TraceStorage* storage = nullptr;
  std::string name;
  sqlite3_module module = {};
};

Table* ToTable(sqlite3_vtab* vtab) {
  return static_cast<Table*>(vtab);
}

Table::RawCursor* ToCursor(sqlite3_vtab_cursor* cursor) {
  return static_cast<Table::RawCursor*>(cursor);
}

std::string TypeToString(Table::ColumnType type) {
  switch (type) {
    case Table::ColumnType::kString:
      return "STRING";
    case Table::ColumnType::kUint:
      return "UNSIGNED INT";
    case Table::ColumnType::kUlong:
      return "UNSIGNED BIG INT";
    case Table::ColumnType::kInt:
      return "INT";
  }
  PERFETTO_CHECK(false);
}

}  // namespace

// static
bool Table::debug = false;

Table::Table() = default;
Table::~Table() = default;

void Table::RegisterInternal(sqlite3* db,
                             const TraceStorage* storage,
                             const std::string& table_name,
                             bool read_write,
                             Factory factory) {
  std::unique_ptr<TableDescriptor> desc(new TableDescriptor());
  desc->storage = storage;
  desc->factory = factory;
  desc->name = table_name;
  sqlite3_module* module = &desc->module;
  memset(module, 0, sizeof(*module));

  auto create_fn = [](sqlite3* xdb, void* arg, int argc,
                      const char* const* argv, sqlite3_vtab** tab, char**) {
    const TableDescriptor* xdesc = static_cast<const TableDescriptor*>(arg);
    auto table = xdesc->factory(xdb, xdesc->storage);

    auto schema = table->CreateSchema(argc, argv);
    auto create_stmt = schema.ToCreateTableStmt();

    int res = sqlite3_declare_vtab(xdb, create_stmt.c_str());
    if (res != SQLITE_OK)
      return res;

    // Freed in xDisconnect().
    table->schema_ = schema;
    table->name_ = xdesc->name;
    *tab = table.release();

    return SQLITE_OK;
  };
  module->xCreate = create_fn;
  module->xConnect = create_fn;

  auto destroy_fn = [](sqlite3_vtab* t) {
    delete ToTable(t);
    return SQLITE_OK;
  };
  module->xDisconnect = destroy_fn;
  module->xDestroy = destroy_fn;

  module->xOpen = [](sqlite3_vtab* t, sqlite3_vtab_cursor** c) {
    return ToTable(t)->OpenInternal(c);
  };

  module->xClose = [](sqlite3_vtab_cursor* c) {
    delete ToCursor(c);
    return SQLITE_OK;
  };

  module->xBestIndex = [](sqlite3_vtab* t, sqlite3_index_info* i) {
    return ToTable(t)->BestIndexInternal(i);
  };

  module->xFilter = [](sqlite3_vtab_cursor* c, int i, const char* s, int a,
                       sqlite3_value** v) {
    return ToCursor(c)->Filter(i, s, a, v);
  };
  module->xNext = [](sqlite3_vtab_cursor* c) {
    return ToCursor(c)->cursor()->Next();
  };
  module->xEof = [](sqlite3_vtab_cursor* c) {
    return ToCursor(c)->cursor()->Eof();
  };
  module->xColumn = [](sqlite3_vtab_cursor* c, sqlite3_context* a, int b) {
    return ToCursor(c)->cursor()->Column(a, b);
  };

  module->xRowid = [](sqlite3_vtab_cursor* c, sqlite3_int64* r) {
    return ToCursor(c)->cursor()->RowId(r);
  };

  module->xFindFunction =
      [](sqlite3_vtab* t, int, const char* name,
         void (**fn)(sqlite3_context*, int, sqlite3_value**),
         void** args) { return ToTable(t)->FindFunction(name, fn, args); };

  if (read_write) {
    module->xUpdate = [](sqlite3_vtab* t, int a, sqlite3_value** v,
                         sqlite3_int64* r) {
      return ToTable(t)->Update(a, v, r);
    };
  }

  int res = sqlite3_create_module_v2(
      db, table_name.c_str(), module, desc.release(),
      [](void* arg) { delete static_cast<TableDescriptor*>(arg); });
  PERFETTO_CHECK(res == SQLITE_OK);
}

int Table::OpenInternal(sqlite3_vtab_cursor** ppCursor) {
  // Freed in xClose().
  *ppCursor = static_cast<sqlite3_vtab_cursor*>(new RawCursor(this));
  return SQLITE_OK;
}

int Table::BestIndexInternal(sqlite3_index_info* idx) {
  QueryConstraints query_constraints;

  for (int i = 0; i < idx->nOrderBy; i++) {
    int column = idx->aOrderBy[i].iColumn;
    bool desc = idx->aOrderBy[i].desc;
    query_constraints.AddOrderBy(column, desc);
  }

  for (int i = 0; i < idx->nConstraint; i++) {
    const auto& cs = idx->aConstraint[i];
    if (!cs.usable)
      continue;
    query_constraints.AddConstraint(cs.iColumn, cs.op);

    // argvIndex is 1-based so use the current size of the vector.
    int argv_index = static_cast<int>(query_constraints.constraints().size());
    idx->aConstraintUsage[i].argvIndex = argv_index;
  }

  BestIndexInfo info;
  info.omit.resize(query_constraints.constraints().size());

  int ret = BestIndex(query_constraints, &info);

  if (Table::debug) {
    PERFETTO_LOG(
        "[%s::BestIndex] constraints=%s orderByConsumed=%d estimatedCost=%d",
        name_.c_str(), query_constraints.ToNewSqlite3String().get(),
        info.order_by_consumed, info.estimated_cost);
  }

  if (ret != SQLITE_OK)
    return ret;

  idx->orderByConsumed = info.order_by_consumed;
  idx->estimatedCost = info.estimated_cost;

  size_t j = 0;
  for (int i = 0; i < idx->nConstraint; i++) {
    const auto& cs = idx->aConstraint[i];
    if (cs.usable)
      idx->aConstraintUsage[i].omit = info.omit[j++];
  }

  if (!info.order_by_consumed)
    query_constraints.ClearOrderBy();

  idx->idxStr = query_constraints.ToNewSqlite3String().release();
  idx->needToFreeIdxStr = true;
  idx->idxNum = ++best_index_num_;

  return SQLITE_OK;
}

int Table::FindFunction(const char*, FindFunctionFn, void**) {
  return 0;
}

int Table::Update(int, sqlite3_value**, sqlite3_int64*) {
  return SQLITE_READONLY;
}

Table::RawCursor::RawCursor(Table* table) : table_(table) {}

int Table::RawCursor::Filter(int idxNum,
                             const char* idxStr,
                             int argc,
                             sqlite3_value** argv) {
  auto* table = ToTable(this->pVtab);
  bool cache_hit = true;
  if (idxNum != table->qc_hash_) {
    table->qc_cache_ = QueryConstraints::FromString(idxStr);
    table->qc_hash_ = idxNum;
    cache_hit = false;
  }
  if (Table::debug) {
    PERFETTO_LOG("[%s::Filter] constraints=%s argc=%d cache_hit=%d",
                 table->name_.c_str(), idxStr, argc, cache_hit);
  }
  PERFETTO_DCHECK(table->qc_cache_.constraints().size() ==
                  static_cast<size_t>(argc));
  cursor_ = table_->CreateCursor(table->qc_cache_, argv);
  return !cursor_ ? SQLITE_ERROR : SQLITE_OK;
}

Table::Cursor::~Cursor() = default;

int Table::Cursor::RowId(sqlite3_int64*) {
  return SQLITE_ERROR;
}

Table::Column::Column(size_t index,
                      std::string name,
                      ColumnType type,
                      bool hidden)
    : index_(index), name_(name), type_(type), hidden_(hidden) {}

Table::Schema::Schema(std::vector<Column> columns,
                      std::vector<size_t> primary_keys)
    : columns_(std::move(columns)), primary_keys_(std::move(primary_keys)) {
  for (size_t i = 0; i < columns_.size(); i++) {
    PERFETTO_CHECK(columns_[i].index() == i);
  }
  for (auto key : primary_keys_) {
    PERFETTO_CHECK(key < columns_.size());
  }
}

Table::Schema::Schema() = default;
Table::Schema::Schema(const Schema&) = default;
Table::Schema& Table::Schema::operator=(const Schema&) = default;

std::string Table::Schema::ToCreateTableStmt() {
  std::string stmt = "CREATE TABLE x(";
  for (const auto& col : columns_) {
    stmt += " " + col.name() + " " + TypeToString(col.type()) + ",";
  }
  stmt += " PRIMARY KEY(";
  for (size_t i = 0; i < primary_keys_.size(); i++) {
    if (i != 0)
      stmt += ", ";
    stmt += columns_[primary_keys_[i]].name();
  }
  stmt += ")) WITHOUT ROWID;";
  return stmt;
}

}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>trace_processor: fix missing noexcept breaking build in Google3<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/table.h"

#include <ctype.h>
#include <string.h>

#include "perfetto/base/logging.h"

namespace perfetto {
namespace trace_processor {

namespace {

struct TableDescriptor {
  Table::Factory factory;
  const TraceStorage* storage = nullptr;
  std::string name;
  sqlite3_module module = {};
};

Table* ToTable(sqlite3_vtab* vtab) {
  return static_cast<Table*>(vtab);
}

Table::RawCursor* ToCursor(sqlite3_vtab_cursor* cursor) {
  return static_cast<Table::RawCursor*>(cursor);
}

std::string TypeToString(Table::ColumnType type) {
  switch (type) {
    case Table::ColumnType::kString:
      return "STRING";
    case Table::ColumnType::kUint:
      return "UNSIGNED INT";
    case Table::ColumnType::kUlong:
      return "UNSIGNED BIG INT";
    case Table::ColumnType::kInt:
      return "INT";
  }
  PERFETTO_CHECK(false);
}

}  // namespace

// static
bool Table::debug = false;

Table::Table() = default;
Table::~Table() = default;

void Table::RegisterInternal(sqlite3* db,
                             const TraceStorage* storage,
                             const std::string& table_name,
                             bool read_write,
                             Factory factory) {
  std::unique_ptr<TableDescriptor> desc(new TableDescriptor());
  desc->storage = storage;
  desc->factory = factory;
  desc->name = table_name;
  sqlite3_module* module = &desc->module;
  memset(module, 0, sizeof(*module));

  auto create_fn = [](sqlite3* xdb, void* arg, int argc,
                      const char* const* argv, sqlite3_vtab** tab, char**) {
    const TableDescriptor* xdesc = static_cast<const TableDescriptor*>(arg);
    auto table = xdesc->factory(xdb, xdesc->storage);

    auto schema = table->CreateSchema(argc, argv);
    auto create_stmt = schema.ToCreateTableStmt();

    int res = sqlite3_declare_vtab(xdb, create_stmt.c_str());
    if (res != SQLITE_OK)
      return res;

    // Freed in xDisconnect().
    table->schema_ = schema;
    table->name_ = xdesc->name;
    *tab = table.release();

    return SQLITE_OK;
  };
  module->xCreate = create_fn;
  module->xConnect = create_fn;

  auto destroy_fn = [](sqlite3_vtab* t) {
    delete ToTable(t);
    return SQLITE_OK;
  };
  module->xDisconnect = destroy_fn;
  module->xDestroy = destroy_fn;

  module->xOpen = [](sqlite3_vtab* t, sqlite3_vtab_cursor** c) {
    return ToTable(t)->OpenInternal(c);
  };

  module->xClose = [](sqlite3_vtab_cursor* c) {
    delete ToCursor(c);
    return SQLITE_OK;
  };

  module->xBestIndex = [](sqlite3_vtab* t, sqlite3_index_info* i) {
    return ToTable(t)->BestIndexInternal(i);
  };

  module->xFilter = [](sqlite3_vtab_cursor* c, int i, const char* s, int a,
                       sqlite3_value** v) {
    return ToCursor(c)->Filter(i, s, a, v);
  };
  module->xNext = [](sqlite3_vtab_cursor* c) {
    return ToCursor(c)->cursor()->Next();
  };
  module->xEof = [](sqlite3_vtab_cursor* c) {
    return ToCursor(c)->cursor()->Eof();
  };
  module->xColumn = [](sqlite3_vtab_cursor* c, sqlite3_context* a, int b) {
    return ToCursor(c)->cursor()->Column(a, b);
  };

  module->xRowid = [](sqlite3_vtab_cursor* c, sqlite3_int64* r) {
    return ToCursor(c)->cursor()->RowId(r);
  };

  module->xFindFunction =
      [](sqlite3_vtab* t, int, const char* name,
         void (**fn)(sqlite3_context*, int, sqlite3_value**),
         void** args) { return ToTable(t)->FindFunction(name, fn, args); };

  if (read_write) {
    module->xUpdate = [](sqlite3_vtab* t, int a, sqlite3_value** v,
                         sqlite3_int64* r) {
      return ToTable(t)->Update(a, v, r);
    };
  }

  int res = sqlite3_create_module_v2(
      db, table_name.c_str(), module, desc.release(),
      [](void* arg) { delete static_cast<TableDescriptor*>(arg); });
  PERFETTO_CHECK(res == SQLITE_OK);
}

int Table::OpenInternal(sqlite3_vtab_cursor** ppCursor) {
  // Freed in xClose().
  *ppCursor = static_cast<sqlite3_vtab_cursor*>(new RawCursor(this));
  return SQLITE_OK;
}

int Table::BestIndexInternal(sqlite3_index_info* idx) {
  QueryConstraints query_constraints;

  for (int i = 0; i < idx->nOrderBy; i++) {
    int column = idx->aOrderBy[i].iColumn;
    bool desc = idx->aOrderBy[i].desc;
    query_constraints.AddOrderBy(column, desc);
  }

  for (int i = 0; i < idx->nConstraint; i++) {
    const auto& cs = idx->aConstraint[i];
    if (!cs.usable)
      continue;
    query_constraints.AddConstraint(cs.iColumn, cs.op);

    // argvIndex is 1-based so use the current size of the vector.
    int argv_index = static_cast<int>(query_constraints.constraints().size());
    idx->aConstraintUsage[i].argvIndex = argv_index;
  }

  BestIndexInfo info;
  info.omit.resize(query_constraints.constraints().size());

  int ret = BestIndex(query_constraints, &info);

  if (Table::debug) {
    PERFETTO_LOG(
        "[%s::BestIndex] constraints=%s orderByConsumed=%d estimatedCost=%d",
        name_.c_str(), query_constraints.ToNewSqlite3String().get(),
        info.order_by_consumed, info.estimated_cost);
  }

  if (ret != SQLITE_OK)
    return ret;

  idx->orderByConsumed = info.order_by_consumed;
  idx->estimatedCost = info.estimated_cost;

  size_t j = 0;
  for (int i = 0; i < idx->nConstraint; i++) {
    const auto& cs = idx->aConstraint[i];
    if (cs.usable)
      idx->aConstraintUsage[i].omit = info.omit[j++];
  }

  if (!info.order_by_consumed)
    query_constraints.ClearOrderBy();

  idx->idxStr = query_constraints.ToNewSqlite3String().release();
  idx->needToFreeIdxStr = true;
  idx->idxNum = ++best_index_num_;

  return SQLITE_OK;
}

int Table::FindFunction(const char*, FindFunctionFn, void**) {
  return 0;
}

int Table::Update(int, sqlite3_value**, sqlite3_int64*) {
  return SQLITE_READONLY;
}

Table::RawCursor::RawCursor(Table* table) : table_(table) {}

int Table::RawCursor::Filter(int idxNum,
                             const char* idxStr,
                             int argc,
                             sqlite3_value** argv) {
  auto* table = ToTable(this->pVtab);
  bool cache_hit = true;
  if (idxNum != table->qc_hash_) {
    table->qc_cache_ = QueryConstraints::FromString(idxStr);
    table->qc_hash_ = idxNum;
    cache_hit = false;
  }
  if (Table::debug) {
    PERFETTO_LOG("[%s::Filter] constraints=%s argc=%d cache_hit=%d",
                 table->name_.c_str(), idxStr, argc, cache_hit);
  }
  PERFETTO_DCHECK(table->qc_cache_.constraints().size() ==
                  static_cast<size_t>(argc));
  cursor_ = table_->CreateCursor(table->qc_cache_, argv);
  return !cursor_ ? SQLITE_ERROR : SQLITE_OK;
}

Table::Cursor::~Cursor() = default;

int Table::Cursor::RowId(sqlite3_int64*) {
  return SQLITE_ERROR;
}

Table::Column::Column(size_t index,
                      std::string name,
                      ColumnType type,
                      bool hidden)
    : index_(index), name_(name), type_(type), hidden_(hidden) {}

Table::Schema::Schema(std::vector<Column> columns,
                      std::vector<size_t> primary_keys)
    : columns_(std::move(columns)), primary_keys_(std::move(primary_keys)) {
  for (size_t i = 0; i < columns_.size(); i++) {
    PERFETTO_CHECK(columns_[i].index() == i);
  }
  for (auto key : primary_keys_) {
    PERFETTO_CHECK(key < columns_.size());
  }
}

Table::Schema::Schema() = default;
Table::Schema::Schema(const Schema&) noexcept = default;
Table::Schema& Table::Schema::operator=(const Schema&) = default;

std::string Table::Schema::ToCreateTableStmt() {
  std::string stmt = "CREATE TABLE x(";
  for (const auto& col : columns_) {
    stmt += " " + col.name() + " " + TypeToString(col.type()) + ",";
  }
  stmt += " PRIMARY KEY(";
  for (size_t i = 0; i < primary_keys_.size(); i++) {
    if (i != 0)
      stmt += ", ";
    stmt += columns_[primary_keys_[i]].name();
  }
  stmt += ")) WITHOUT ROWID;";
  return stmt;
}

}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>


<commit_before>// @(#)root/tree:$Id$
// Author: Rene Brun   05/02/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// A TSelector object is used by the TTree::Draw, TTree::Scan,            //
// TTree::Process to navigate in a TTree and make selections.             //
// It contains the following main methods:                                //
//                                                                        //
// void TSelector::Init(TTree *t). Called every time a new TTree is       //
//    attached.                                                           //
// void TSelector::Begin(). This method is called before looping on the   //
//    events in the Tree. The user can create his histograms in this      //
//    function. When using PROOF Begin() is called on the client only.    //
//    Histogram creation should preferable be done in SlaveBegin() in     //
//    that case.                                                          //
// void TSelector::SlaveBegin(). This method is called on each PROOF      //
//    worker node. The user can create his histograms in this method.     //
//    In local mode this method is called on the client too.              //
//                                                                        //
// Bool_t TSelector::Notify(). This method is called at the first entry   //
//    of a new file in a chain.                                           //
//                                                                        //
// Bool_t TSelector::Process(Long64_t entry). This method is called       //
//    to process an event. It is the user's responsability to read        //
//    the corresponding entry in memory (may be just a partial read).     //
//    Once the entry is in memory one can apply a selection and if the    //
//    event is selected histograms can be filled. Processing stops        //
//    when this function returns kFALSE. This function combines the       //
//    next two functions in one, avoiding to have to maintain state       //
//    in the class to communicate between these two functions.             //
//    See WARNING below about entry.                                      //
//    This method is used by PROOF.                                       //
// Bool_t TSelector::ProcessCut(Long64_t entry). This method is called    //
//    before processing entry. It is the user's responsability to read    //
//    the corresponding entry in memory (may be just a partial read).     //
//    The function returns kTRUE if the entry must be processed,          //
//    kFALSE otherwise. This method is obsolete, use Process().           //
//    See WARNING below about entry.                                      //
// void TSelector::ProcessFill(Long64_t entry). This method is called     //
//    for all selected events. User fills histograms in this function.    //
//    This method is obsolete, use Process().                             //
//    See WARNING below about entry.                                      //
// void TSelector::SlaveTerminate(). This method is called at the end of  //
//    the loop on all PROOF worker nodes. In local mode this method is    //
//    called on the client too.                                           //
// void TSelector::Terminate(). This method is called at the end of       //
//    the loop on all events. When using PROOF Terminate() is call on     //
//    the client only. Typically one performs the fits on the produced    //
//    histograms or write the histograms to file in this method.          //
//                                                                        //
// WARNING when a selector is used with a TChain:                         //
//    in the Process, ProcessCut, ProcessFill function, you must use      //
//    the pointer to the current Tree to call GetEntry(entry).            //
//    entry is always the local entry number in the current tree.         //
//    Assuming that fChain is the pointer to the TChain being processed,  //
//    use fChain->GetTree()->GetEntry(entry);                             //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TSystem.h"
#include "TTree.h"
#include "TError.h"
#include "TSelectorCint.h"
#include "TClass.h"
#include "TInterpreter.h"

ClassImp(TSelector)

//______________________________________________________________________________
TSelector::TSelector() : TObject()
{
   // Default selector ctor.

   fStatus = 0;
   fAbort  = kContinue;
   fObject = 0;
   fInput  = 0;
   fOutput = new TSelectorList;
   fOutput->SetOwner();
}

//______________________________________________________________________________
TSelector::~TSelector()
{
   // Selector destructor.

   delete fOutput;
}

//______________________________________________________________________________
void TSelector::Abort(const char *why, EAbort what)
{
   // Abort processing. If what = kAbortProcess, the Process() loop will be
   // aborted. If what = kAbortFile, the current file in a chain will be
   // aborted and the processing will continue with the next file, if there
   // is no next file then Process() will be aborted. Abort() can also  be
   // called from Begin(), SlaveBegin(), Init() and Notify(). After abort
   // the SlaveTerminate() and Terminate() are always called. The abort flag
   // can be checked in these methods using GetAbort().

   fAbort = what;
   TString mess = "Abort";
   if (fAbort == kAbortProcess)
      mess = "AbortProcess";
   else if (fAbort == kAbortFile)
      mess = "AbortFile";

   Info(mess, "%s", why);
}

//______________________________________________________________________________
TSelector *TSelector::GetSelector(const char *filename)
{
   // The code in filename is loaded (interpreted or compiled, see below),
   // filename must contain a valid class implementation derived from TSelector.
   //
   // If filename is of the form file.C, the file will be interpreted.
   // If filename is of the form file.C++, the file file.C will be compiled
   // and dynamically loaded. The corresponding binary file and shared
   // library will be deleted at the end of the function.
   // If filename is of the form file.C+, the file file.C will be compiled
   // and dynamically loaded. At next call, if file.C is older than file.o
   // and file.so, the file.C is not compiled, only file.so is loaded.
   //
   // The static function returns a pointer to a TSelector object

   // If the filename does not contain "." assume class is compiled in
   TString localname;
   Bool_t fromFile = kFALSE;
   if (strchr(filename, '.') != 0) {
      //Interpret/compile filename via CINT
      localname  = ".L ";
      localname += filename;
      gROOT->ProcessLine(localname);
      fromFile = kTRUE;
   }

   //loop on all classes known to CINT to find the class on filename
   //that derives from TSelector
   const char *basename = gSystem->BaseName(filename);
   if (!basename) {
      ::Error("TSelector::GetSelector","unable to determine the classname for file %s", filename);
      return 0;
   }
   TString aclicmode,args,io;
   localname = gSystem->SplitAclicMode(basename,aclicmode,args,io);
   Bool_t isCompiled = !fromFile || aclicmode.Length()>0;
   if (localname.Last('.') != kNPOS)
      localname.Remove(localname.Last('.'));

   // if a file was not specified, try to load the class via the interpreter;
   // this returns 0 (== failure) in the case the class is already in memory
   // but does not have a dictionary, so we just raise a flag for better
   // diagnostic in the case the class is not found in the CINT ClassInfo table.
   Bool_t autoloaderr = kFALSE;
   if (!fromFile && gCint->AutoLoad(localname) != 1)
      autoloaderr = kTRUE;

   ClassInfo_t *cl = gCint->ClassInfo_Factory();
   Bool_t ok = kFALSE;
   while (gCint->ClassInfo_Next(cl)) {
      if (localname == gCint->ClassInfo_FullName(cl)) {
         if (gCint->ClassInfo_IsBase(cl,"TSelector")) ok = kTRUE;
         break;
      }
   }
   if (!ok) {
      if (fromFile) {
         ::Error("TSelector::GetSelector",
         "file %s does not have a valid class deriving from TSelector", filename);
      } else {
         if (autoloaderr)
            ::Error("TSelector::GetSelector", "class %s could not be loaded", filename);
         else
            ::Error("TSelector::GetSelector",
                    "class %s does not exist or does not derive from TSelector", filename);
      }
      return 0;
   }

   // we can now create an instance of the class
   TSelector *selector = (TSelector*)gCint->ClassInfo_New(cl);
   if (!selector || isCompiled) return selector;

   //interpreted selector: cannot be used as such
   //create a fake selector
   TSelectorCint *select = new TSelectorCint();
   select->Build(selector, cl);
   gCint->ClassInfo_Delete(cl);
   return select;
}

//______________________________________________________________________________
Bool_t TSelector::IsStandardDraw(const char *selec)
{
   // Find out if this is a standard selection used for Draw actions
   // (either TSelectorDraw, TProofDraw or deriving from them).

   // Make sure we have a name
   if (!selec) {
      ::Info("TSelector::IsStandardDraw",
             "selector name undefined - do nothing");
      return kFALSE;
   }

   Bool_t stdselec = kFALSE;
   if (!strchr(selec, '.')) {
      if (strstr(selec, "TSelectorDraw")) {
         stdselec = kTRUE;
      } else {
         TClass *cl = TClass::GetClass(selec);
         if (cl && (cl->InheritsFrom("TProofDraw") ||
                    cl->InheritsFrom("TSelectorDraw")))
            stdselec = kTRUE;
      }
   }

   // We are done
   return stdselec;
}
<commit_msg>* Simplify and clarify doc for SlaveBegin() versus Begin()  * Wording: use TTree "entry" instead of "event"<commit_after>// @(#)root/tree:$Id$
// Author: Rene Brun   05/02/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

////////////////////////////////////////////////////////////////////////////
//                                                                        //
// A TSelector object is used by the TTree::Draw, TTree::Scan,            //
// TTree::Process to navigate in a TTree and make selections.             //
// It contains the following main methods:                                //
//                                                                        //
// void TSelector::Init(TTree *t). Called every time a new TTree is       //
//    attached.                                                           //
//                                                                        //
// void TSelector::SlaveBegin(). Create e.g. histograms in this method.   //
//    This method is called (with or without PROOF) before looping on the //
//    entries in the Tree. When using PROOF, this method is called on     //
//    each worker node.                                                   //
// void TSelector::Begin(). Mostly for backward compatibility; use        //
//    SlaveBegin() instead. Both methods are called before looping on the //
//    entries in the Tree. When using PROOF, Begin() is called on the     //
//    client only.                                                        //
//                                                                        //
// Bool_t TSelector::Notify(). This method is called at the first entry   //
//    of a new file in a chain.                                           //
//                                                                        //
// Bool_t TSelector::Process(Long64_t entry). This method is called       //
//    to process an entry. It is the user's responsability to read        //
//    the corresponding entry in memory (may be just a partial read).     //
//    Once the entry is in memory one can apply a selection and if the    //
//    entry is selected histograms can be filled. Processing stops        //
//    when this function returns kFALSE. This function combines the       //
//    next two functions in one, avoiding to have to maintain state       //
//    in the class to communicate between these two functions.            //
//    See WARNING below about entry.                                      //
//    This method is used by PROOF.                                       //
// Bool_t TSelector::ProcessCut(Long64_t entry). This method is called    //
//    before processing entry. It is the user's responsability to read    //
//    the corresponding entry in memory (may be just a partial read).     //
//    The function returns kTRUE if the entry must be processed,          //
//    kFALSE otherwise. This method is obsolete, use Process().           //
//    See WARNING below about entry.                                      //
// void TSelector::ProcessFill(Long64_t entry). This method is called     //
//    for all selected entries. User fills histograms in this function.   //
//    This method is obsolete, use Process().                             //
//    See WARNING below about entry.                                      //
// void TSelector::SlaveTerminate(). This method is called at the end of  //
//    the loop on all PROOF worker nodes. In local mode this method is    //
//    called on the client too.                                           //
// void TSelector::Terminate(). This method is called at the end of       //
//    the loop on all entries. When using PROOF Terminate() is call on    //
//    the client only. Typically one performs the fits on the produced    //
//    histograms or write the histograms to file in this method.          //
//                                                                        //
// WARNING when a selector is used with a TChain:                         //
//    in the Process, ProcessCut, ProcessFill function, you must use      //
//    the pointer to the current Tree to call GetEntry(entry).            //
//    entry is always the local entry number in the current tree.         //
//    Assuming that fChain is the pointer to the TChain being processed,  //
//    use fChain->GetTree()->GetEntry(entry);                             //
//                                                                        //
////////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TSystem.h"
#include "TTree.h"
#include "TError.h"
#include "TSelectorCint.h"
#include "TClass.h"
#include "TInterpreter.h"

ClassImp(TSelector)

//______________________________________________________________________________
TSelector::TSelector() : TObject()
{
   // Default selector ctor.

   fStatus = 0;
   fAbort  = kContinue;
   fObject = 0;
   fInput  = 0;
   fOutput = new TSelectorList;
   fOutput->SetOwner();
}

//______________________________________________________________________________
TSelector::~TSelector()
{
   // Selector destructor.

   delete fOutput;
}

//______________________________________________________________________________
void TSelector::Abort(const char *why, EAbort what)
{
   // Abort processing. If what = kAbortProcess, the Process() loop will be
   // aborted. If what = kAbortFile, the current file in a chain will be
   // aborted and the processing will continue with the next file, if there
   // is no next file then Process() will be aborted. Abort() can also  be
   // called from Begin(), SlaveBegin(), Init() and Notify(). After abort
   // the SlaveTerminate() and Terminate() are always called. The abort flag
   // can be checked in these methods using GetAbort().

   fAbort = what;
   TString mess = "Abort";
   if (fAbort == kAbortProcess)
      mess = "AbortProcess";
   else if (fAbort == kAbortFile)
      mess = "AbortFile";

   Info(mess, "%s", why);
}

//______________________________________________________________________________
TSelector *TSelector::GetSelector(const char *filename)
{
   // The code in filename is loaded (interpreted or compiled, see below),
   // filename must contain a valid class implementation derived from TSelector.
   //
   // If filename is of the form file.C, the file will be interpreted.
   // If filename is of the form file.C++, the file file.C will be compiled
   // and dynamically loaded. The corresponding binary file and shared
   // library will be deleted at the end of the function.
   // If filename is of the form file.C+, the file file.C will be compiled
   // and dynamically loaded. At next call, if file.C is older than file.o
   // and file.so, the file.C is not compiled, only file.so is loaded.
   //
   // The static function returns a pointer to a TSelector object

   // If the filename does not contain "." assume class is compiled in
   TString localname;
   Bool_t fromFile = kFALSE;
   if (strchr(filename, '.') != 0) {
      //Interpret/compile filename via CINT
      localname  = ".L ";
      localname += filename;
      gROOT->ProcessLine(localname);
      fromFile = kTRUE;
   }

   //loop on all classes known to CINT to find the class on filename
   //that derives from TSelector
   const char *basename = gSystem->BaseName(filename);
   if (!basename) {
      ::Error("TSelector::GetSelector","unable to determine the classname for file %s", filename);
      return 0;
   }
   TString aclicmode,args,io;
   localname = gSystem->SplitAclicMode(basename,aclicmode,args,io);
   Bool_t isCompiled = !fromFile || aclicmode.Length()>0;
   if (localname.Last('.') != kNPOS)
      localname.Remove(localname.Last('.'));

   // if a file was not specified, try to load the class via the interpreter;
   // this returns 0 (== failure) in the case the class is already in memory
   // but does not have a dictionary, so we just raise a flag for better
   // diagnostic in the case the class is not found in the CINT ClassInfo table.
   Bool_t autoloaderr = kFALSE;
   if (!fromFile && gCint->AutoLoad(localname) != 1)
      autoloaderr = kTRUE;

   ClassInfo_t *cl = gCint->ClassInfo_Factory();
   Bool_t ok = kFALSE;
   while (gCint->ClassInfo_Next(cl)) {
      if (localname == gCint->ClassInfo_FullName(cl)) {
         if (gCint->ClassInfo_IsBase(cl,"TSelector")) ok = kTRUE;
         break;
      }
   }
   if (!ok) {
      if (fromFile) {
         ::Error("TSelector::GetSelector",
         "file %s does not have a valid class deriving from TSelector", filename);
      } else {
         if (autoloaderr)
            ::Error("TSelector::GetSelector", "class %s could not be loaded", filename);
         else
            ::Error("TSelector::GetSelector",
                    "class %s does not exist or does not derive from TSelector", filename);
      }
      return 0;
   }

   // we can now create an instance of the class
   TSelector *selector = (TSelector*)gCint->ClassInfo_New(cl);
   if (!selector || isCompiled) return selector;

   //interpreted selector: cannot be used as such
   //create a fake selector
   TSelectorCint *select = new TSelectorCint();
   select->Build(selector, cl);
   gCint->ClassInfo_Delete(cl);
   return select;
}

//______________________________________________________________________________
Bool_t TSelector::IsStandardDraw(const char *selec)
{
   // Find out if this is a standard selection used for Draw actions
   // (either TSelectorDraw, TProofDraw or deriving from them).

   // Make sure we have a name
   if (!selec) {
      ::Info("TSelector::IsStandardDraw",
             "selector name undefined - do nothing");
      return kFALSE;
   }

   Bool_t stdselec = kFALSE;
   if (!strchr(selec, '.')) {
      if (strstr(selec, "TSelectorDraw")) {
         stdselec = kTRUE;
      } else {
         TClass *cl = TClass::GetClass(selec);
         if (cl && (cl->InheritsFrom("TProofDraw") ||
                    cl->InheritsFrom("TSelectorDraw")))
            stdselec = kTRUE;
      }
   }

   // We are done
   return stdselec;
}
<|endoftext|>


<commit_before>// -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
// vi: set ts=2 noet:
//
// Copyright (c) 2016 Sergey Lyskov <sergey.lyskov@jhu.edu>
//
// All rights reserved. Use of this source code is governed by a
// MIT license that can be found in the LICENSE file.

/// @file   binder/enum.cpp
/// @brief  Binding generation for C++ enums
/// @author Sergey Lyskov

#include <enum.hpp>

#include <type.hpp>
#include <util.hpp>

#include <fmt/format.h>

#include <clang/AST/ASTContext.h>

using namespace llvm;
using namespace clang;

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

using namespace fmt::literals;

namespace binder {

/// extract include needed for this generator and add it to includes vector
void add_relevant_includes(clang::EnumDecl const *E, IncludeSet &includes, int level)
{
	if( !includes.add_decl(E, level) ) return;
	add_relevant_include_for_decl(E, includes);
}

// Generate binding for given function: py::enum_<MyEnum>(module, "MyEnum")...
std::string bind_enum(std::string const & module, EnumDecl *E)
{
	string name { E->getNameAsString() };
	string qualified_name { E->getQualifiedNameAsString() };

	string r = "\tpybind11::enum_<{}>({}, \"{}\", \"{}\")\n"_format(qualified_name, module, name, generate_documentation_string_for_declaration(E));

	for(auto e = E->enumerator_begin(); e != E->enumerator_end(); ++e) {
		r += "\t\t.value(\"{}\", {})\n"_format(e->getNameAsString(), e->getQualifiedNameAsString());
	}
	r.pop_back();

	return r + ( E->isScopedUsingClassTag() ? ";\n\n" : "\n\t\t.export_values();\n\n" );
}

/// Generate string id that uniquly identify C++ binding object. For functions this is function prototype and for classes forward declaration.
string EnumBinder::id() const
{
	return E->getQualifiedNameAsString();
}

/// check if generator can create binding
bool EnumBinder::bindable() const
{
	if( E->isCXXInstanceMember()  or  E->isCXXClassMember() ) return false;
	else return true;
}

/// check if user requested binding for the given declaration
void EnumBinder::request_bindings_and_skipping(Config const &config)
{
	if( config.is_namespace_binding_requested( namespace_from_named_decl(E) ) ) Binder::request_bindings();
}

/// extract include needed for this generator and add it to includes vector
void EnumBinder::add_relevant_includes(IncludeSet &includes) const
{
	binder::add_relevant_includes(E, includes, 0);
}

/// generate binding code for this object and all its dependencies
void EnumBinder::bind(Context &context)
{
	if( is_binded() ) return;

	string const module_variable_name = context.module_variable_name( namespace_from_named_decl(E) );

	code()  = "\t" + generate_comment_for_declaration(E);
	code() += bind_enum(module_variable_name, E) + ";\n\n";
}

} // namespace binder
<commit_msg>enum include should also reference definition headers<commit_after>// -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
// vi: set ts=2 noet:
//
// Copyright (c) 2016 Sergey Lyskov <sergey.lyskov@jhu.edu>
//
// All rights reserved. Use of this source code is governed by a
// MIT license that can be found in the LICENSE file.

/// @file   binder/enum.cpp
/// @brief  Binding generation for C++ enums
/// @author Sergey Lyskov

#include <enum.hpp>

#include <type.hpp>
#include <util.hpp>

#include <fmt/format.h>

#include <clang/AST/ASTContext.h>

using namespace llvm;
using namespace clang;

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

using namespace fmt::literals;

namespace binder {

/// extract include needed for this generator and add it to includes vector
void add_relevant_includes(clang::EnumDecl const *E, IncludeSet &includes, int level)
{
	if( !includes.add_decl(E, level) ) return;
	add_relevant_include_for_decl(E, includes);

	add_relevant_include_for_decl(E->getDefinition(), includes);
}

// Generate binding for given function: py::enum_<MyEnum>(module, "MyEnum")...
std::string bind_enum(std::string const & module, EnumDecl *E)
{
	string name { E->getNameAsString() };
	string qualified_name { E->getQualifiedNameAsString() };

	string r = "\tpybind11::enum_<{}>({}, \"{}\", \"{}\")\n"_format(qualified_name, module, name, generate_documentation_string_for_declaration(E));

	for(auto e = E->enumerator_begin(); e != E->enumerator_end(); ++e) {
		r += "\t\t.value(\"{}\", {})\n"_format(e->getNameAsString(), e->getQualifiedNameAsString());
	}
	r.pop_back();

	return r + ( E->isScopedUsingClassTag() ? ";\n\n" : "\n\t\t.export_values();\n\n" );
}

/// Generate string id that uniquly identify C++ binding object. For functions this is function prototype and for classes forward declaration.
string EnumBinder::id() const
{
	return E->getQualifiedNameAsString();
}

/// check if generator can create binding
bool EnumBinder::bindable() const
{
	if( E->isCXXInstanceMember()  or  E->isCXXClassMember() ) return false;
	else return true;
}

/// check if user requested binding for the given declaration
void EnumBinder::request_bindings_and_skipping(Config const &config)
{
	if( config.is_namespace_binding_requested( namespace_from_named_decl(E) ) ) Binder::request_bindings();
}

/// extract include needed for this generator and add it to includes vector
void EnumBinder::add_relevant_includes(IncludeSet &includes) const
{
	binder::add_relevant_includes(E, includes, 0);
}

/// generate binding code for this object and all its dependencies
void EnumBinder::bind(Context &context)
{
	if( is_binded() ) return;

	string const module_variable_name = context.module_variable_name( namespace_from_named_decl(E) );

	code()  = "\t" + generate_comment_for_declaration(E);
	code() += bind_enum(module_variable_name, E) + ";\n\n";
}

} // namespace binder
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/nest/p9_l2_flush.C $       */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p9_l2_flush.H
/// @brief Flush the P9 L2 cache (FAPI)
///
/// *HWP HWP Owner   : Benjamin Gass <bgass@us.ibm.com>
/// *HWP FW Owner    : Bilicon Patil  <bilpatil@in.ibm.com>
/// *HWP Team        : Quad
/// *HWP Consumed by : FSP
/// *HWP Level       : 2
///

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <p9_quad_scom_addresses.H>
#include <p9_l2_flush.H>

//------------------------------------------------------------------------------
// Constant definitions
//------------------------------------------------------------------------------

// L2 Purge Engine Command Register bit/field definitions
enum
{
    PURGE_CMD_TRIGGER_BIT            = 0,
    PURGE_CMD_REG_BUSY               = 9,
    PURGE_CMD_PRGSM_BUSY_ON_THIS_BIT = 10,
    PURGE_CMD_PRGSM_BUSY_BIT         = 11,
    PURGE_CMD_ERR_BIT                = 29,
    PURGE_CMD_TYPE_BIT               = 1,
    PURGE_CMD_MEM_BIT                = 17,
    PURGE_CMD_BANK_BIT               = 28,
    PURGE_CMD_CGC_BIT                = 20
};

// L2 Purge Engine Command Register bit/field Lengths
enum
{
    PURGE_CMD_TYPE_BIT_LENGTH   = 4,
    PURGE_CMD_MEM_BIT_LENGTH    = 3,
    PURGE_CMD_BANK_BIT_LENGTH   = 1,
    PURGE_CMD_CGC_BIT_LENGTH    = 8
};

// polling constants
enum
{
    P9_L2_FLUSH_HW_NS_DELAY     = 10000, // unit is nano seconds
    P9_L2_FLUSH_SIM_CYCLE_DELAY = 12000, // unit is cycles
    P9_L2_FLUSH_MAX_POLLS       = 200    // unit is cycles
};

//------------------------------------------------------------------------------
// Function definitions
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
///
/// @brief l2_flush_start: Utility subroutine to initiate L2 cache flush
///                        via purge engine
/// @param[in]  i_target Ex target
/// @param[in]  i_regAddr The scom address to use
/// @param[in]  i_purgeData Structure having values for MEM, CGC, BANK
///                         passed by the user
/// @return  FAPI2_RC_SUCCESS if purge operation was started,
///          RC_P9_L2_FLUSH_PURGE_REQ_OUTSTANDING if a prior purge
///          operation has not yet completed
///          else FAPI getscom/putscom return code for failing operation
//------------------------------------------------------------------------------
fapi2::ReturnCode l2_flush_start(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_target,
    const uint32_t i_regAddr,
    const p9core::purgeData_t& i_purgeData)
{
    fapi2::buffer<uint64_t> l_cmdReg;
    fapi2::buffer<uint64_t> l_purgeCmd;

    FAPI_INF("l2_flush_start: Enter");

    // ensure that purge engine is idle before starting flush
    // poll Purge Engine status
    FAPI_DBG("Reading L2 Purge Engine Command Register to check status");
    FAPI_TRY(fapi2::getScom(i_target, i_regAddr, l_cmdReg));

    // check to see if this reg is idle and ready to accept a new command
    FAPI_ASSERT(!l_cmdReg.getBit<PURGE_CMD_REG_BUSY>(),
                fapi2::P9_L2_FLUSH_PURGE_REQ_OUTSTANDING()
                .set_TARGET(i_target)
                .set_CMD_REG(l_cmdReg)
                .set_CMD_REG_ADDR(i_regAddr),
                "Previous purge request has not completed for target");

    // write PURGE_CMD_TRIGGER bit in Purge Engine Command Register
    // ensure PURGE_CMD_TYPE/MEM/CGC/BANK are clear to specify flush
    // of entire cache
    FAPI_DBG("Write L2 Purge Engine Command Register to initiate cache flush");
    l_purgeCmd.insert<PURGE_CMD_TYPE_BIT,
                      PURGE_CMD_TYPE_BIT_LENGTH>(i_purgeData.iv_cmdType);

    l_purgeCmd.insert<PURGE_CMD_MEM_BIT,
                      PURGE_CMD_MEM_BIT_LENGTH>(i_purgeData.iv_cmdMem);

    l_purgeCmd.insert<PURGE_CMD_BANK_BIT,
                      PURGE_CMD_BANK_BIT_LENGTH>(i_purgeData.iv_cmdBank);

    l_purgeCmd.insert<PURGE_CMD_CGC_BIT,
                      PURGE_CMD_CGC_BIT_LENGTH>(i_purgeData.iv_cmdCGC);

    l_purgeCmd.setBit<PURGE_CMD_TRIGGER_BIT>();

    FAPI_TRY(fapi2::putScom(i_target, i_regAddr, l_purgeCmd));

fapi_try_exit:
    return fapi2::current_err;
}

//------------------------------------------------------------------------------
///
/// @brief l2_flush_check_status: Utility subroutine to poll L2 purge
///                                    engine status, looking for clean idle
///                                    state
/// @param[in] i_target EX chiplet target
/// @param[in] i_regAddr Purge engine register SCOM address
/// @return FAPI2_RC_SUCCESS if engine status returns as idle (with no errors)
///         before maximum number of polls has been reached
///         RC_P9_L2_FLUSH_CMD_ERROR
///              if purge command error reported,
///         RC_P9_L2_FLUSH_CMD_TIMEOUT
///              if purge operation did not complete prior to polling limit,
///         else FAPI getscom/putscom return code for failing operation
///
//------------------------------------------------------------------------------
fapi2::ReturnCode l2_flush_check_status(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_target,
    const uint32_t i_regAddr)
{
    fapi2::buffer<uint64_t> l_cmdReg;
    uint32_t l_polls = 1;

    FAPI_INF("l2_flush_check_status: Enter");

    while(1)
    {
        // poll Purge Engine status
        FAPI_DBG("Reading L2 Purge Engine Command Register to check status");
        FAPI_TRY(fapi2::getScom(i_target, i_regAddr, l_cmdReg));

        // check state of PURGE_CMD_ERR
        FAPI_ASSERT(!l_cmdReg.getBit<PURGE_CMD_ERR_BIT>(),
                    fapi2::P9_L2_FLUSH_CMD_ERROR()
                    .set_TARGET(i_target)
                    .set_CMD_REG(l_cmdReg)
                    .set_CMD_REG_ADDR(i_regAddr),
                    "Purge failed. PURGE_CMD_ERR_BIT set");

        // check to see if this reg is idle and ready to accept a new command
        if (!l_cmdReg.getBit<PURGE_CMD_REG_BUSY>())
        {
            FAPI_DBG("Purge engine idle");
            break;
        }

        // engine busy, dump status
        FAPI_DBG("Purge engine busy (reg_busy = %d, busy_on_this = %d,"
                 " sm_busy = %d)",
                 l_cmdReg.getBit<PURGE_CMD_REG_BUSY>(),
                 l_cmdReg.getBit<PURGE_CMD_PRGSM_BUSY_ON_THIS_BIT>(),
                 l_cmdReg.getBit<PURGE_CMD_PRGSM_BUSY_BIT>());

        // check if loop count has expired
        FAPI_ASSERT((l_polls < P9_L2_FLUSH_MAX_POLLS),
                    fapi2::P9_L2_FLUSH_CMD_TIMEOUT()
                    .set_TARGET(i_target)
                    .set_CMD_REG(l_cmdReg)
                    .set_CMD_REG_ADDR(i_regAddr)
                    .set_NUMBER_OF_ATTEMPTS(l_polls),
                    "Purge engine still busy after %d loops", l_polls);

        // l_polls left, delay prior to next poll
        FAPI_DBG("%d loops done, delaying before next poll", l_polls);

        FAPI_TRY(fapi2::delay(P9_L2_FLUSH_HW_NS_DELAY,
                              P9_L2_FLUSH_SIM_CYCLE_DELAY),
                 "fapi delay Error");

        l_polls++;
    }

fapi_try_exit:
    return fapi2::current_err;
}

//------------------------------------------------------------------------------
// Hardware Procedure
//------------------------------------------------------------------------------
fapi2::ReturnCode p9_l2_flush(const fapi2::Target < fapi2::TARGET_TYPE_EX >
                              & i_target,
                              const p9core::purgeData_t& i_purgeData)
{
    FAPI_DBG("i_purgeData [iv_cmdType: 0x%x] [iv_cmdMem : 0x%x] "
             "[iv_cmdBank: 0x%x] [iv_cmdCGC : 0x%x]", i_purgeData.iv_cmdType,
             i_purgeData.iv_cmdMem, i_purgeData.iv_cmdBank, i_purgeData.iv_cmdCGC);

    uint32_t l_regAddr = EX_PRD_PURGE_CMD_REG;

    // initiate flush
    FAPI_TRY(l2_flush_start(i_target, l_regAddr, i_purgeData));

    // check that flush completes and the purge engine is idle
    // before exiting
    FAPI_TRY(l2_flush_check_status(i_target, l_regAddr));

fapi_try_exit:
    FAPI_INF("l2_flush, Ex: Exit");
    return fapi2::current_err;
}
<commit_msg>L3 Update - p9_l2/l3_flush.C<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/nest/p9_l2_flush.C $       */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_l2_flush.H
/// @brief Flush the P9 L2 cache (FAPI)
///
/// *HWP HWP Owner   : Benjamin Gass <bgass@us.ibm.com>
/// *HWP FW Owner    : Thi Tran <thi@us.ibm.com>
/// *HWP Team        : Quad
/// *HWP Consumed by : FSP and SBE
/// *HWP Level       : 3
///

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <p9_l2_flush.H>
#include <p9_quad_scom_addresses.H>
#include <p9_quad_scom_addresses_fld.H>

//------------------------------------------------------------------------------
// Constant definitions
//------------------------------------------------------------------------------

// polling constants
enum
{
    P9_L2_FLUSH_HW_NS_DELAY     = 10000, // unit is nano seconds
    P9_L2_FLUSH_SIM_CYCLE_DELAY = 12000, // unit is cycles
    P9_L2_FLUSH_MAX_POLLS       = 200    // unit is cycles
};

//------------------------------------------------------------------------------
// Function definitions
//------------------------------------------------------------------------------

///-----------------------------------------------------------------------------
/// @brief Utility subroutine to initiate L2 cache flush via purge engine.
///
/// @param[in]  i_target    EX target
/// @param[in]  i_regAddr   The scom address to use
/// @param[in]  i_purgeData Structure having values for MEM, CGC, BANK
///                         passed by the user
///
/// @return  FAPI2_RC_SUCCESS if purge operation was started,
///          RC_P9_L2_FLUSH_PURGE_REQ_OUTSTANDING if a prior purge
///          operation has not yet completed
///          else FAPI getscom/putscom return code for failing operation
///-----------------------------------------------------------------------------
fapi2::ReturnCode l2_flush_start(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_target,
    const uint32_t i_regAddr,
    const p9core::purgeData_t& i_purgeData)
{
    fapi2::buffer<uint64_t> l_cmdReg;
    fapi2::buffer<uint64_t> l_purgeCmd;

    FAPI_DBG("l2_flush_start: Enter");

    // ensure that purge engine is idle before starting flush
    // poll Purge Engine status
    FAPI_DBG("Reading L2 Purge Engine Command Register to check status");
    FAPI_TRY(fapi2::getScom(i_target, i_regAddr, l_cmdReg));

    // check to see if this reg is idle and ready to accept a new command
    FAPI_ASSERT(!l_cmdReg.getBit<EX_PRD_PURGE_CMD_REG_BUSY>(),
                fapi2::P9_L2_FLUSH_PURGE_REQ_OUTSTANDING()
                .set_TARGET(i_target)
                .set_CMD_REG(l_cmdReg)
                .set_CMD_REG_ADDR(i_regAddr),
                "Previous purge request has not completed for target");

    // write PURGE_CMD_TRIGGER bit in Purge Engine Command Register
    // ensure PURGE_CMD_TYPE/MEM/CGC/BANK are clear to specify flush
    // of entire cache
    FAPI_DBG("Write L2 Purge Engine Command Register to initiate cache flush");
    l_purgeCmd.insert<EX_PRD_PURGE_CMD_REG_TYPE,
                      EX_PRD_PURGE_CMD_REG_TYPE_LEN>(i_purgeData.iv_cmdType);

    l_purgeCmd.insert<EX_PRD_PURGE_CMD_REG_MEM,
                      EX_PRD_PURGE_CMD_REG_MEM_LEN>(i_purgeData.iv_cmdMem);

    l_purgeCmd.insert<EX_PRD_PURGE_CMD_REG_BANK, 1>(i_purgeData.iv_cmdBank);

    l_purgeCmd.insert<EX_PRD_PURGE_CMD_REG_CGC,
                      EQ_PRD_PURGE_CMD_REG_CGC_LEN>(i_purgeData.iv_cmdCGC);

    l_purgeCmd.setBit<EX_PRD_PURGE_CMD_REG_TRIGGER>();

    FAPI_TRY(fapi2::putScom(i_target, i_regAddr, l_purgeCmd));

fapi_try_exit:
    FAPI_DBG("l2_flush_start: Exit");
    return fapi2::current_err;
}

///-----------------------------------------------------------------------------
/// @brief Utility subroutine to poll L2 purge engine status, looking for
///        clean idle state.
///
/// @param[in] i_target EX chiplet target
/// @param[in] i_regAddr Purge engine register SCOM address
///
/// @return FAPI2_RC_SUCCESS if engine status returns as idle (with no errors)
///         before maximum number of polls has been reached
///         RC_P9_L2_FLUSH_CMD_ERROR
///              if purge command error reported,
///         RC_P9_L2_FLUSH_CMD_TIMEOUT
///              if purge operation did not complete prior to polling limit,
///         else FAPI getscom/putscom return code for failing operation
///-----------------------------------------------------------------------------
fapi2::ReturnCode l2_flush_check_status(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_target,
    const uint32_t i_regAddr)
{
    fapi2::buffer<uint64_t> l_cmdReg;
    uint32_t l_polls = 1;

    FAPI_DBG("l2_flush_check_status: Enter");

    while(1)
    {
        // poll Purge Engine status
        FAPI_DBG("Reading L2 Purge Engine Command Register to check status");
        FAPI_TRY(fapi2::getScom(i_target, i_regAddr, l_cmdReg));

        // check state of PURGE_CMD_ERR
        FAPI_ASSERT(!l_cmdReg.getBit<EX_PRD_PURGE_CMD_REG_ERR>(),
                    fapi2::P9_L2_FLUSH_CMD_ERROR()
                    .set_TARGET(i_target)
                    .set_CMD_REG(l_cmdReg)
                    .set_CMD_REG_ADDR(i_regAddr),
                    "Purge failed. EX_PRD_PURGE_CMD_REG_ERR set");

        // check to see if this reg is idle and ready to accept a new command
        if (!l_cmdReg.getBit<EX_PRD_PURGE_CMD_REG_BUSY>())
        {
            FAPI_DBG("Purge engine idle");
            break;
        }

        // engine busy, dump status
        FAPI_DBG("Purge engine busy (reg_busy = %d, busy_on_this = %d,"
                 " sm_busy = %d)",
                 l_cmdReg.getBit<EX_PRD_PURGE_CMD_REG_BUSY>(),
                 l_cmdReg.getBit<EX_PRD_PURGE_CMD_REG_PRGSM_BUSY_ON_THIS>(),
                 l_cmdReg.getBit<EX_PRD_PURGE_CMD_REG_PRGSM_BUSY>());

        // check if loop count has expired
        FAPI_ASSERT((l_polls < P9_L2_FLUSH_MAX_POLLS),
                    fapi2::P9_L2_FLUSH_CMD_TIMEOUT()
                    .set_TARGET(i_target)
                    .set_CMD_REG(l_cmdReg)
                    .set_CMD_REG_ADDR(i_regAddr)
                    .set_NUMBER_OF_ATTEMPTS(l_polls),
                    "Purge engine still busy after %d loops", l_polls);

        // l_polls left, delay prior to next poll
        FAPI_DBG("%d loops done, delaying before next poll", l_polls);

        FAPI_TRY(fapi2::delay(P9_L2_FLUSH_HW_NS_DELAY,
                              P9_L2_FLUSH_SIM_CYCLE_DELAY));

        l_polls++;
    }

fapi_try_exit:
    FAPI_DBG("l2_flush_check_status: Exit");
    return fapi2::current_err;
}

//------------------------------------------------------------------------------
// Hardware Procedure
// See doxygen in header file.
//------------------------------------------------------------------------------
fapi2::ReturnCode p9_l2_flush(
    const fapi2::Target <fapi2::TARGET_TYPE_EX>& i_target,
    const p9core::purgeData_t& i_purgeData)
{
    FAPI_DBG("Entering p9_l2_flush: i_purgeData [iv_cmdType: 0x%x] "
             "[iv_cmdMem : 0x%x] [iv_cmdBank: 0x%x] [iv_cmdCGC : 0x%x]",
             i_purgeData.iv_cmdType, i_purgeData.iv_cmdMem,
             i_purgeData.iv_cmdBank, i_purgeData.iv_cmdCGC);

    uint32_t l_regAddr = EX_PRD_PURGE_CMD_REG;

    // initiate flush
    FAPI_TRY(l2_flush_start(i_target, l_regAddr, i_purgeData));

    // check that flush completes and the purge engine is idle
    // before exiting
    FAPI_TRY(l2_flush_check_status(i_target, l_regAddr));

fapi_try_exit:
    FAPI_DBG("p9_l2_flush: Exit");
    return fapi2::current_err;
}
<|endoftext|>


<commit_before>// first working version
// no runtime info was generated
// repo: https://github.com/hun-nemethpeter/clang in branch typid_ast
// direct link to patch: https://github.com/llvm-mirror/clang/compare/master...hun-nemethpeter:typid_ast

#include "ast.h"

struct Test
{
  bool member1;
  char member2;
};

int main()
{
  static_assert(typeid<Test>.name() == "Test");
  static_assert(typeid<Test>.members().size() == 2);
  static_assert(typeid<Test>.members()[0].name() == "member1");
  static_assert(typeid<Test>.members()[0].type().name() == "bool");
  static_assert(typeid<Test>.members()[1].name() == "member2");
  static_assert(typeid<Test>.members()[1].type().name() == "char");
  static_assert(typeid<Test>.bases().size() == 0);
  static_assert(typeid<Test2>.name() == "Test2");

  return 0;
}
<commit_msg>Update test.cpp<commit_after>// first working version
// no runtime info was generated
// repo: https://github.com/hun-nemethpeter/clang in branch typid_ast
// direct link to patch: https://github.com/llvm-mirror/clang/compare/master...hun-nemethpeter:typid_ast

#include "ast.h"

struct Test
{
  bool member1;
  char member2;
};

int main()
{
  static_assert(typeid<Test>.name() == "Test");
  static_assert(typeid<Test>.members().size() == 2);
  static_assert(typeid<Test>.members()[0].name() == "member1");
  static_assert(typeid<Test>.members()[0].type().name() == "bool");
  static_assert(typeid<Test>.members()[1].name() == "member2");
  static_assert(typeid<Test>.members()[1].type().name() == "char");
  static_assert(typeid<Test>.bases().size() == 0);

  return 0;
}
<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/OlympusDecompressor.h"
#include "common/Common.h"                // for uint32, ushort16, uchar8
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpMSB.h"                // for BitPumpMSB
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for min
#include <array>                          // for array, array<>::value_type
#include <cassert>                        // for assert
#include <cmath>                          // for abs
#include <cstdlib>                        // for abs
#include <memory>                         // for unique_ptr
#include <type_traits>                    // for enable_if_t, is_integral

namespace {

// Normally, we'd just use std::signbit(int) here. But, some (non-conforming?)
// compilers do not provide that overload, so the code simply fails to compile.
// One could cast the int to the double, but at least right now that results
// in a horrible code. So let's just provide our own signbit(). It compiles to
// the exact same code as the std::signbit(int).
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
constexpr __attribute__((const)) bool SignBit(T x) {
  return x < 0;
}

} // namespace

namespace rawspeed {

OlympusDecompressor::OlympusDecompressor(const RawImage& img) : mRaw(img) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != 2)
    ThrowRDE("Unexpected component count / data type");

  const uint32 w = mRaw->dim.x;
  const uint32 h = mRaw->dim.y;

  if (w == 0 || h == 0 || w % 2 != 0 || w > 10400 || h > 7792)
    ThrowRDE("Unexpected image dimensions found: (%u; %u)", w, h);
}

/* This is probably the slowest decoder of them all.
 * I cannot see any way to effectively speed up the prediction
 * phase, which is by far the slowest part of this algorithm.
 * Also there is no way to multithread this code, since prediction
 * is based on the output of all previous pixel (bar the first four)
 */

void OlympusDecompressor::decompress(ByteStream input) const {
  assert(mRaw->dim.y > 0);
  assert(mRaw->dim.x > 0);
  assert(mRaw->dim.x % 2 == 0);

  uchar8* data = mRaw->getData();
  int pitch = mRaw->pitch;

  /* Build a table to quickly look up "high" value */
  std::unique_ptr<char[]> bittable(new char[4096]); // NOLINT

  for (int i = 0; i < 4096; i++) {
    int b = i;
    int high;
    for (high = 0; high < 12; high++)
      if ((b >> (11 - high)) & 1)
        break;
    bittable[i] = std::min(12, high);
  }

  input.skipBytes(7);
  BitPumpMSB bits(input);

  for (uint32 y = 0; y < static_cast<uint32>(mRaw->dim.y); y++) {
    std::array<std::array<int, 3>, 2> acarry{{}};
    std::array<int, 2> nw{{}};

    auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
    bool y_border = y < 2;
    bool border = true;
    for (uint32 x = 0; x < static_cast<uint32>(mRaw->dim.x); x++) {
      int c = x & 1;

      std::array<int, 3>& carry = acarry[c];

      bits.fill();
      int i = 2 * (carry[2] < 3);
      int nbits;
      for (nbits = 2 + i; static_cast<ushort16>(carry[0]) >> (nbits + i);
           nbits++)
        ;

      int b = bits.peekBitsNoFill(15);
      int sign = (b >> 14) * -1;
      int low = (b >> 12) & 3;
      int high = bittable[b & 4095];

      // Skip bytes used above or read bits
      if (high == 12) {
        bits.skipBitsNoFill(15);
        high = bits.getBits(16 - nbits) >> 1;
      } else
        bits.skipBitsNoFill(high + 1 + 3);

      carry[0] = (high << nbits) | bits.getBits(nbits);
      int diff = (carry[0] ^ sign) + carry[1];
      carry[1] = (diff * 3 + carry[1]) >> 5;
      carry[2] = carry[0] > 16 ? 0 : carry[2] + 1;

      int pred;
      if (border) {
        if (y_border && x < 2)
          pred = 0;
        else {
          if (y_border)
            pred = dest[x - 2];
          else {
            pred = dest[-pitch + (static_cast<int>(x))];
            nw[c] = pred;
          }
        }
      } else {
        // Have local variables for values used several tiles
        // (having a "ushort16 *dst_up" that caches dest[-pitch+((int)x)] is
        // actually slower, probably stack spill or aliasing)
        int up = dest[-pitch + (static_cast<int>(x))];
        int leftMinusNw = dest[x - 2] - nw[c];
        int upMinusNw = up - nw[c];
        // Check if sign is different, and they are both not zero
        if ((SignBit(leftMinusNw) ^ SignBit(upMinusNw)) &&
            (leftMinusNw != 0 && upMinusNw != 0)) {
          if (std::abs(leftMinusNw) > 32 || std::abs(upMinusNw) > 32)
            pred = dest[x - 2] + upMinusNw;
          else
            pred = (dest[x - 2] + up) >> 1;
        } else
          pred = std::abs(leftMinusNw) > std::abs(upMinusNw) ? dest[x - 2] : up;

        nw[c] = up;
      }

      dest[x] = pred + ((diff * 4) | low);

      if (c)
        border = y_border;
    }
  }
}

} // namespace rawspeed
<commit_msg>OlympusDecompressor: get rid of 'nw' caching.<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/OlympusDecompressor.h"
#include "common/Common.h"                // for uint32, ushort16, uchar8
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpMSB.h"                // for BitPumpMSB
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for min
#include <array>                          // for array, array<>::value_type
#include <cassert>                        // for assert
#include <cmath>                          // for abs
#include <cstdlib>                        // for abs
#include <memory>                         // for unique_ptr
#include <type_traits>                    // for enable_if_t, is_integral

namespace {

// Normally, we'd just use std::signbit(int) here. But, some (non-conforming?)
// compilers do not provide that overload, so the code simply fails to compile.
// One could cast the int to the double, but at least right now that results
// in a horrible code. So let's just provide our own signbit(). It compiles to
// the exact same code as the std::signbit(int).
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
constexpr __attribute__((const)) bool SignBit(T x) {
  return x < 0;
}

} // namespace

namespace rawspeed {

OlympusDecompressor::OlympusDecompressor(const RawImage& img) : mRaw(img) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != 2)
    ThrowRDE("Unexpected component count / data type");

  const uint32 w = mRaw->dim.x;
  const uint32 h = mRaw->dim.y;

  if (w == 0 || h == 0 || w % 2 != 0 || w > 10400 || h > 7792)
    ThrowRDE("Unexpected image dimensions found: (%u; %u)", w, h);
}

/* This is probably the slowest decoder of them all.
 * I cannot see any way to effectively speed up the prediction
 * phase, which is by far the slowest part of this algorithm.
 * Also there is no way to multithread this code, since prediction
 * is based on the output of all previous pixel (bar the first four)
 */

void OlympusDecompressor::decompress(ByteStream input) const {
  assert(mRaw->dim.y > 0);
  assert(mRaw->dim.x > 0);
  assert(mRaw->dim.x % 2 == 0);

  uchar8* data = mRaw->getData();
  int pitch = mRaw->pitch;

  /* Build a table to quickly look up "high" value */
  std::unique_ptr<char[]> bittable(new char[4096]); // NOLINT

  for (int i = 0; i < 4096; i++) {
    int b = i;
    int high;
    for (high = 0; high < 12; high++)
      if ((b >> (11 - high)) & 1)
        break;
    bittable[i] = std::min(12, high);
  }

  input.skipBytes(7);
  BitPumpMSB bits(input);

  for (uint32 y = 0; y < static_cast<uint32>(mRaw->dim.y); y++) {
    std::array<std::array<int, 3>, 2> acarry{{}};

    auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
    bool y_border = y < 2;
    bool border = true;
    for (uint32 x = 0; x < static_cast<uint32>(mRaw->dim.x); x++) {
      int c = x & 1;

      std::array<int, 3>& carry = acarry[c];

      bits.fill();
      int i = 2 * (carry[2] < 3);
      int nbits;
      for (nbits = 2 + i; static_cast<ushort16>(carry[0]) >> (nbits + i);
           nbits++)
        ;

      int b = bits.peekBitsNoFill(15);
      int sign = (b >> 14) * -1;
      int low = (b >> 12) & 3;
      int high = bittable[b & 4095];

      // Skip bytes used above or read bits
      if (high == 12) {
        bits.skipBitsNoFill(15);
        high = bits.getBits(16 - nbits) >> 1;
      } else
        bits.skipBitsNoFill(high + 1 + 3);

      carry[0] = (high << nbits) | bits.getBits(nbits);
      int diff = (carry[0] ^ sign) + carry[1];
      carry[1] = (diff * 3 + carry[1]) >> 5;
      carry[2] = carry[0] > 16 ? 0 : carry[2] + 1;

      int pred;
      if (border) {
        if (y_border && x < 2)
          pred = 0;
        else {
          if (y_border)
            pred = dest[x - 2];
          else {
            pred = dest[-pitch + (static_cast<int>(x))];
          }
        }
      } else {
        // Have local variables for values used several tiles
        // (having a "ushort16 *dst_up" that caches dest[-pitch+((int)x)] is
        // actually slower, probably stack spill or aliasing)
        int up = dest[-pitch + (static_cast<int>(x))];
        int leftMinusNw =
            dest[x - 2] - dest[-pitch + (static_cast<int>(x)) - 2];
        int upMinusNw = up - dest[-pitch + (static_cast<int>(x)) - 2];
        // Check if sign is different, and they are both not zero
        if ((SignBit(leftMinusNw) ^ SignBit(upMinusNw)) &&
            (leftMinusNw != 0 && upMinusNw != 0)) {
          if (std::abs(leftMinusNw) > 32 || std::abs(upMinusNw) > 32)
            pred = dest[x - 2] + upMinusNw;
          else
            pred = (dest[x - 2] + up) >> 1;
        } else
          pred = std::abs(leftMinusNw) > std::abs(upMinusNw) ? dest[x - 2] : up;
      }

      dest[x] = pred + ((diff * 4) | low);

      if (c)
        border = y_border;
    }
  }
}

} // namespace rawspeed
<|endoftext|>