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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/
#include "QmitkOtsuAction.h"

// MITK
#include <itkOtsuMultipleThresholdsImageFilter.h>
#include <mitkRenderingManager.h>
#include <mitkImage.h>
#include <mitkImageCast.h>
#include <mitkITKImageImport.h>
#include <mitkLevelWindowProperty.h>

#include <mitkLookupTable.h>
#include <mitkLookupTableProperty.h>

// ITK
#include <itkMultiplyImageFilter.h>

// Qt
#include <QDialog>
#include <QVBoxLayout>
#include <QApplication>
#include <QList>
#include <QLabel>
#include <QMessageBox>

using namespace berry;
using namespace mitk;
using namespace std;

QmitkOtsuAction::QmitkOtsuAction()
: m_OtsuSegmentationDialog(NULL)
{
}

QmitkOtsuAction::~QmitkOtsuAction()
{
}

void QmitkOtsuAction::Run(const QList<DataNode::Pointer> &selectedNodes)
{
  this->m_DataNode = selectedNodes[0];
  //this->m_selectedNodes = selectedNodes;

  m_OtsuSegmentationDialog = new QDialog(QApplication::activeWindow(),Qt::WindowTitleHint | Qt::WindowSystemMenuHint);

  QVBoxLayout *layout = new QVBoxLayout;
  layout->setContentsMargins(0, 0, 0, 0);
  QHBoxLayout* spinBoxLayout = new QHBoxLayout;
  QHBoxLayout* buttonLayout = new QHBoxLayout;

  m_OtsuSpinBox = new QSpinBox;
  m_OtsuSpinBox->setRange(2, 32);
  m_OtsuSpinBox->setValue(2);

  m_OtsuPushButton = new QPushButton("OK");
  QPushButton* CancelButton = new QPushButton("Cancel");

  connect(m_OtsuPushButton, SIGNAL(clicked()), this, SLOT(OtsuSegmentationDone()));
  connect(CancelButton, SIGNAL(clicked()), m_OtsuSegmentationDialog, SLOT(reject()));

  QLabel* numberOfThresholdsLabel = new QLabel("Select number of Regions of Interest:");
  numberOfThresholdsLabel->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
  layout->addWidget(numberOfThresholdsLabel);
  layout->addLayout(spinBoxLayout);
  spinBoxLayout->addSpacing(50);
  spinBoxLayout->addWidget(m_OtsuSpinBox);
  spinBoxLayout->addSpacing(50);
  layout->addLayout(buttonLayout);
  buttonLayout->addWidget(m_OtsuPushButton);
  buttonLayout->addWidget(CancelButton);

  m_OtsuSegmentationDialog->setLayout(layout);
  m_OtsuSegmentationDialog->setFixedSize(300, 80);

  m_OtsuSegmentationDialog->open();
}

void QmitkOtsuAction::OtsuSegmentationDone()
{

  /*
  if (result == QDialog::Rejected)
  m_ThresholdingToolManager->ActivateTool(-1);*/

  this->PerformOtsuSegmentation();

  m_OtsuSegmentationDialog->deleteLater();
  m_OtsuSegmentationDialog = NULL;

  //m_ThresholdingToolManager->SetReferenceData(NULL);
  //m_ThresholdingToolManager->SetWorkingData(NULL);

  RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkOtsuAction::SetDataStorage(DataStorage *dataStorage)
{
  m_DataStorage = dataStorage;
}

void QmitkOtsuAction::SetFunctionality(QtViewPart* /*functionality*/)
{
}

void QmitkOtsuAction::PerformOtsuSegmentation()
{
  this->m_OtsuSegmentationDialog->setCursor(Qt::WaitCursor);

  int numberOfThresholds = this->m_OtsuSpinBox->value() - 1;
  int proceed;

  QMessageBox* messageBox = new QMessageBox(QMessageBox::Question, NULL, "The otsu segmentation computation may take several minutes depending on the number of Regions you selected. Proceed anyway?", QMessageBox::Ok | QMessageBox::Cancel);
  if (numberOfThresholds >= 5)
  {
    proceed = messageBox->exec();
    if (proceed != QMessageBox::Ok) return;
  }

  mitk::Image::Pointer mitkImage = 0;

  mitkImage = dynamic_cast<mitk::Image*>( this->m_DataNode->GetData() );

  try
  {
    // get selected mitk image
    const unsigned short dim = 3;
    typedef short InputPixelType;
    typedef unsigned char OutputPixelType;

    typedef itk::Image< InputPixelType, dim > InputImageType;
    typedef itk::Image< OutputPixelType, dim > OutputImageType;

    //typedef itk::OtsuThresholdImageFilter< InputImageType, OutputImageType > FilterType;
    typedef itk::OtsuMultipleThresholdsImageFilter< InputImageType, OutputImageType > FilterType;
    //typedef itk::MultiplyImageFilter< OutputImageType, OutputImageType, OutputImageType> MultiplyFilterType;
    //typedef itk::RandomImageSource< OutputImageType> RandomImageSourceType;
    //typedef itk::ImageRegionIterator< OutputImageType > ImageIteratorType;

    FilterType::Pointer filter = FilterType::New();
    //MultiplyFilterType::Pointer multiplyImageFilter = MultiplyFilterType::New();
    //RandomImageSourceType::Pointer randomImageSource = RandomImageSourceType::New();

    filter->SetNumberOfThresholds(numberOfThresholds);
    //filter->SetLabelOffset(0);
    /*
    filter->SetOutsideValue( 1 );
    filter->SetInsideValue( 0 );*/

    InputImageType::Pointer itkImage;
    mitk::CastToItkImage(mitkImage, itkImage);

    filter->SetInput( itkImage );
//    filter->UpdateOutputInformation();

    //multiplyImageFilter->SetInput1(filter->GetOutput());
    //OutputImageType::Pointer constantImage = OutputImageType::New();
    //constantImage->SetLargestPossibleRegion(filter->GetOutput()->GetLargestPossibleRegion());
    //constantImage->SetBufferedRegion(filter->GetOutput()->GetLargestPossibleRegion());
    //constantImage->Allocate();
    //ImageIteratorType it(constantImage, constantImage->GetLargestPossibleRegion());
    //while (!it.IsAtEnd())
    //{
    //  it.Set(1);
    //  ++it;
    //}

    ////randomImageSource->SetSize(filter->GetOutput()->GetLargestPossibleRegion().GetSize());
    ////multiplyImageFilter->SetInput2(randomImageSource->GetOutput());
    //multiplyImageFilter->SetInput2(constantImage);

    filter->Update();
    //multiplyImageFilter->Update();

    mitk::DataNode::Pointer resultNode = mitk::DataNode::New();
    std::string nameOfResultImage = this->m_DataNode->GetName();
    nameOfResultImage.append("Otsu");
    resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) );
    resultNode->SetProperty("binary", mitk::BoolProperty::New(false) );
    resultNode->SetProperty("use color", mitk::BoolProperty::New(false) );

    mitk::LookupTable::Pointer lut = mitk::LookupTable::New();

    mitk::LookupTableProperty::Pointer prop = mitk::LookupTableProperty::New(lut);

    //resultNode->GetProperty(prop, "LookupTable");

    vtkLookupTable *lookupTable = vtkLookupTable::New();
    lookupTable->SetHueRange(1.0, 0.0);
    lookupTable->SetSaturationRange(1.0, 1.0);
    lookupTable->SetValueRange(1.0, 1.0);
    lookupTable->SetTableRange(-1.0, 1.0);
    lookupTable->Build();

    lut->SetVtkLookupTable(lookupTable);

    prop->SetLookupTable(lut);
    resultNode->SetProperty("LookupTable",prop);

    mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New();
    mitk::LevelWindow levelwindow;
    levelwindow.SetRangeMinMax(0, numberOfThresholds);
    levWinProp->SetLevelWindow( levelwindow );
    resultNode->SetProperty( "levelwindow", levWinProp );

    //resultNode->SetData( mitk::ImportItkImage ( filter->GetOutput() ) );
    resultNode->SetData( mitk::ImportItkImage ( filter->GetOutput() ) );

    this->m_DataStorage->Add(resultNode, this->m_DataNode);

    this->m_OtsuSegmentationDialog->setCursor(Qt::ArrowCursor);

  }
  catch( std::exception& err )
  {
    MITK_ERROR(this->GetClassName()) << err.what();
  }
  }<commit_msg>Set the right rendering property.<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/
#include "QmitkOtsuAction.h"

// MITK
#include <itkOtsuMultipleThresholdsImageFilter.h>
#include <mitkRenderingManager.h>
#include <mitkImage.h>
#include <mitkImageCast.h>
#include <mitkITKImageImport.h>
#include <mitkLevelWindowProperty.h>
#include <mitkRenderingModeProperty.h>

#include <mitkLookupTable.h>
#include <mitkLookupTableProperty.h>

// ITK
#include <itkMultiplyImageFilter.h>

// Qt
#include <QDialog>
#include <QVBoxLayout>
#include <QApplication>
#include <QList>
#include <QLabel>
#include <QMessageBox>

using namespace berry;
using namespace mitk;
using namespace std;

QmitkOtsuAction::QmitkOtsuAction()
: m_OtsuSegmentationDialog(NULL)
{
}

QmitkOtsuAction::~QmitkOtsuAction()
{
}

void QmitkOtsuAction::Run(const QList<DataNode::Pointer> &selectedNodes)
{
  this->m_DataNode = selectedNodes[0];
  //this->m_selectedNodes = selectedNodes;

  m_OtsuSegmentationDialog = new QDialog(QApplication::activeWindow(),Qt::WindowTitleHint | Qt::WindowSystemMenuHint);

  QVBoxLayout *layout = new QVBoxLayout;
  layout->setContentsMargins(0, 0, 0, 0);
  QHBoxLayout* spinBoxLayout = new QHBoxLayout;
  QHBoxLayout* buttonLayout = new QHBoxLayout;

  m_OtsuSpinBox = new QSpinBox;
  m_OtsuSpinBox->setRange(2, 32);
  m_OtsuSpinBox->setValue(2);

  m_OtsuPushButton = new QPushButton("OK");
  QPushButton* CancelButton = new QPushButton("Cancel");

  connect(m_OtsuPushButton, SIGNAL(clicked()), this, SLOT(OtsuSegmentationDone()));
  connect(CancelButton, SIGNAL(clicked()), m_OtsuSegmentationDialog, SLOT(reject()));

  QLabel* numberOfThresholdsLabel = new QLabel("Select number of Regions of Interest:");
  numberOfThresholdsLabel->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
  layout->addWidget(numberOfThresholdsLabel);
  layout->addLayout(spinBoxLayout);
  spinBoxLayout->addSpacing(50);
  spinBoxLayout->addWidget(m_OtsuSpinBox);
  spinBoxLayout->addSpacing(50);
  layout->addLayout(buttonLayout);
  buttonLayout->addWidget(m_OtsuPushButton);
  buttonLayout->addWidget(CancelButton);

  m_OtsuSegmentationDialog->setLayout(layout);
  m_OtsuSegmentationDialog->setFixedSize(300, 80);

  m_OtsuSegmentationDialog->open();
}

void QmitkOtsuAction::OtsuSegmentationDone()
{
  this->PerformOtsuSegmentation();

  m_OtsuSegmentationDialog->deleteLater();
  m_OtsuSegmentationDialog = NULL;

  RenderingManager::GetInstance()->RequestUpdateAll();
}

void QmitkOtsuAction::SetDataStorage(DataStorage *dataStorage)
{
  m_DataStorage = dataStorage;
}

void QmitkOtsuAction::SetFunctionality(QtViewPart* /*functionality*/)
{
}

void QmitkOtsuAction::PerformOtsuSegmentation()
{
  this->m_OtsuSegmentationDialog->setCursor(Qt::WaitCursor);

  int numberOfThresholds = this->m_OtsuSpinBox->value() - 1;
  int proceed;

  QMessageBox* messageBox = new QMessageBox(QMessageBox::Question, NULL, "The otsu segmentation computation may take several minutes depending on the number of Regions you selected. Proceed anyway?", QMessageBox::Ok | QMessageBox::Cancel);
  if (numberOfThresholds >= 5)
  {
    proceed = messageBox->exec();
    if (proceed != QMessageBox::Ok) return;
  }

  mitk::Image::Pointer mitkImage = 0;

  mitkImage = dynamic_cast<mitk::Image*>( this->m_DataNode->GetData() );

  try
  {
    // get selected mitk image
    const unsigned short dim = 3;
    typedef short InputPixelType;
    typedef unsigned char OutputPixelType;

    typedef itk::Image< InputPixelType, dim > InputImageType;
    typedef itk::Image< OutputPixelType, dim > OutputImageType;

    typedef itk::OtsuMultipleThresholdsImageFilter< InputImageType, OutputImageType > FilterType;

    FilterType::Pointer filter = FilterType::New();

    filter->SetNumberOfThresholds(numberOfThresholds);

    InputImageType::Pointer itkImage;
    mitk::CastToItkImage(mitkImage, itkImage);

    filter->SetInput( itkImage );

    filter->Update();

    mitk::DataNode::Pointer resultNode = mitk::DataNode::New();
    std::string nameOfResultImage = this->m_DataNode->GetName();
    nameOfResultImage.append("Otsu");
    resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) );
    resultNode->SetProperty("binary", mitk::BoolProperty::New(false) );

    mitk::RenderingModeProperty::Pointer renderingMode = mitk::RenderingModeProperty::New();
    renderingMode->SetValue( mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR );
    resultNode->SetProperty("Image Rendering.Mode", renderingMode);

    mitk::LookupTable::Pointer lut = mitk::LookupTable::New();

    mitk::LookupTableProperty::Pointer prop = mitk::LookupTableProperty::New(lut);

    vtkLookupTable *lookupTable = vtkLookupTable::New();
    lookupTable->SetHueRange(1.0, 0.0);
    lookupTable->SetSaturationRange(1.0, 1.0);
    lookupTable->SetValueRange(1.0, 1.0);
    lookupTable->SetTableRange(-1.0, 1.0);
    lookupTable->Build();

    lut->SetVtkLookupTable(lookupTable);

    prop->SetLookupTable(lut);
    resultNode->SetProperty("LookupTable",prop);

    mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New();
    mitk::LevelWindow levelwindow;
    levelwindow.SetRangeMinMax(0, numberOfThresholds);
    levWinProp->SetLevelWindow( levelwindow );
    resultNode->SetProperty( "levelwindow", levWinProp );

    resultNode->SetData( mitk::ImportItkImage ( filter->GetOutput() ) );

    this->m_DataStorage->Add(resultNode, this->m_DataNode);

    this->m_OtsuSegmentationDialog->setCursor(Qt::ArrowCursor);

  }
  catch( std::exception& err )
  {
    MITK_ERROR(this->GetClassName()) << err.what();
  }
  }<|endoftext|>


<commit_before>#include "TiLDA_MKe.h"

#include "Arduino.h"

TiLDA_MKe::TiLDA_MKe() :
  glcd(LCD_CS, LCD_A0, LCD_RESET)
{
  // GLCD setup
  pinMode(LCD_POWER, OUTPUT);
  digitalWrite(LCD_POWER, LOW);

  /*
   * I think the EMF board def. puts this on a PWM pin
   * but keeping it on digital makes it easier to toggle
   */
  pinMode(LCD_BACKLIGHT, OUTPUT);

  // Configure buttons
  buttons.addButton(BUTTON_LIGHT);
  buttons.addButton(BUTTON_SCREEN_RIGHT);
  buttons.addButton(BUTTON_SCREEN_LEFT);
  buttons.addButton(BUTTON_A);
  buttons.addButton(BUTTON_B);
  buttons.addButton(BUTTON_UP);
  buttons.addButton(BUTTON_RIGHT);
  buttons.addButton(BUTTON_DOWN);
  buttons.addButton(BUTTON_LEFT);
  buttons.addButton(BUTTON_CENTER);

  // LED setup
  setLEDs(0, 0, 0);

  // Battery monitor setup
  pinMode(MCP_STAT, INPUT_PULLUP);
  pinMode(VBATT_MON, INPUT);
}

/**
 * Sets the state of the backlight.
 *
 * @param state State to set backlight to (1 or 0)
 */
void TiLDA_MKe::setBacklight(uint8_t state)
{
  digitalWrite(LCD_BACKLIGHT, state);
}

/**
 * Gets the state of the backlight.
 *
 * @returns Backlight state
 */
uint8_t TiLDA_MKe::backlight()
{
  return digitalRead(LCD_BACKLIGHT);
}

/**
 * Flips the state of the backlight then returns the new state.
 *
 * @returns New backlight state
 */
uint8_t TiLDA_MKe::toggleBacklight()
{
  digitalWrite(LCD_BACKLIGHT, !backlight());
  return backlight();
}

/**
 * Sets the colour and brightness of the RGB LEDs.
 *
 * @param led LED to set (1 or 2)
 * @param r Red intensity
 * @param g Green intensity
 * @param b Blue intensity
 */
void TiLDA_MKe::setLED(uint8_t led, uint8_t r, uint8_t g, uint8_t b)
{
  switch(led)
  {
    case 1:
      analogWrite(LED1_RED, r);
      analogWrite(LED1_GREEN, g);
      analogWrite(LED1_BLUE, b);
      break;
    case 2:
      analogWrite(LED2_RED, r);
      analogWrite(LED2_GREEN, g);
      analogWrite(LED2_BLUE, b);
      break;
    default:
      return;
  }
}

/**
 * Sets both RGB LEDs to the same colour.
 *
 * @param r Red intensity
 * @param g Green intensity
 * @param b Blue intensity
 */
void TiLDA_MKe::setLEDs(uint8_t r, uint8_t g, uint8_t b)
{
  setLED(1, r, g, b);
  setLED(2, r, g, b);
}

/**
 * Gets an approximation of the battery percentage.
 *
 * Note that the value is only accurate when not charging.
 *
 * @return Approx battery percentage
 */
uint8_t TiLDA_MKe::getBatteryPercentage()
{
  return (analogRead(VBATT_MON) - PMIC_BATTERY_FLAT) * PMIC_BATTERY_PERCENT_RATIO;
}

/**
 * Gets the battery voltage.
 *
 * @return Battery voltage
 */
float TiLDA_MKe::getBatteryVoltage()
{
  return (analogRead(VBATT_MON) * (3.3 / 512));
}

/**
 * Tests if the batter is being charged.
 *
 * @return True if charging, false otherwise
 */
bool TiLDA_MKe::isCharging()
{
  return !digitalRead(MCP_STAT);
}

/**
 * Prints a block of text in a given area, wrapping on a given character.
 *
 * @param x X coordinate of the top left corner of the area
 * @param y Y coordinate of the top left corner of the area
 * @param w Width of the area
 * @param h Height of the area
 * @param text Text string
 * @param delimiter Character to delimit text on
 */
void TiLDA_MKe::drawWrappedStr(uint8_t x, uint8_t y,
    uint8_t w, uint8_t h, char *text, char delimiter)
{
  char *last_newline_ptr = text;
  uint8_t y_increment = glcd.getFontLineSpacing();
  uint8_t pos_y = y + y_increment;

  while(*last_newline_ptr != '\0')
  {
    char *cut_point = getNewlinePtr(last_newline_ptr+1, w, delimiter);
    int16_t len = cut_point - last_newline_ptr;
    char *sub_str = new char[len + 1];

    char *copy_start = last_newline_ptr;
    if(*copy_start == delimiter)
      ++copy_start;

    memcpy(sub_str, copy_start, len);
    sub_str[len] = '\0';

    glcd.drawStr(x, pos_y, sub_str);

    delete[] sub_str;

    last_newline_ptr = cut_point;
    pos_y += y_increment;

    if(pos_y > h - y)
      return;
  }
}

/**
 * Determines if a string is too long to fit in a certain pixel width.
 *
 * @param string Pointer to the string
 * @param len Length of the sub string
 * @param limit Width in pixels the text must be less than
 * @return True if the substring is wider then limit
 */
bool TiLDA_MKe::subStringOverLength(char *string, uint8_t len, uint8_t limit)
{
  char *sub_str = new char[len + 1];
  memcpy(sub_str, string, len);
  sub_str[len] = '\0';
  uint8_t width = glcd.getStrWidth(sub_str);
  delete[] sub_str;
  return width > limit;
}

/**
 * Gets a pointer to the position to wrap text for the GLCD.
 *
 * @param string String pointer
 * @param width Max. text width in pixels
 * @param delimiter Char. to delimit text on
 * @return Pointer where the text should be split
 */
char *TiLDA_MKe::getNewlinePtr(char *string, uint8_t width, char delimiter)
{
  uint8_t len = 1;
  bool over_length = false;

  while(len < strlen(string))
  {
    if(subStringOverLength(string, len, width))
    {
      over_length = true;
      break;
    }
    len++;
  }

  if(over_length)
  {
    while(len > 0)
    {
      if(string[len] == delimiter)
        return string+len;

      len--;
    }
  }
  else
  {
    return string+len;
  }
}
<commit_msg>Small change to height checking<commit_after>#include "TiLDA_MKe.h"

#include "Arduino.h"

TiLDA_MKe::TiLDA_MKe() :
  glcd(LCD_CS, LCD_A0, LCD_RESET)
{
  // GLCD setup
  pinMode(LCD_POWER, OUTPUT);
  digitalWrite(LCD_POWER, LOW);

  /*
   * I think the EMF board def. puts this on a PWM pin
   * but keeping it on digital makes it easier to toggle
   */
  pinMode(LCD_BACKLIGHT, OUTPUT);

  // Configure buttons
  buttons.addButton(BUTTON_LIGHT);
  buttons.addButton(BUTTON_SCREEN_RIGHT);
  buttons.addButton(BUTTON_SCREEN_LEFT);
  buttons.addButton(BUTTON_A);
  buttons.addButton(BUTTON_B);
  buttons.addButton(BUTTON_UP);
  buttons.addButton(BUTTON_RIGHT);
  buttons.addButton(BUTTON_DOWN);
  buttons.addButton(BUTTON_LEFT);
  buttons.addButton(BUTTON_CENTER);

  // LED setup
  setLEDs(0, 0, 0);

  // Battery monitor setup
  pinMode(MCP_STAT, INPUT_PULLUP);
  pinMode(VBATT_MON, INPUT);
}

/**
 * Sets the state of the backlight.
 *
 * @param state State to set backlight to (1 or 0)
 */
void TiLDA_MKe::setBacklight(uint8_t state)
{
  digitalWrite(LCD_BACKLIGHT, state);
}

/**
 * Gets the state of the backlight.
 *
 * @returns Backlight state
 */
uint8_t TiLDA_MKe::backlight()
{
  return digitalRead(LCD_BACKLIGHT);
}

/**
 * Flips the state of the backlight then returns the new state.
 *
 * @returns New backlight state
 */
uint8_t TiLDA_MKe::toggleBacklight()
{
  digitalWrite(LCD_BACKLIGHT, !backlight());
  return backlight();
}

/**
 * Sets the colour and brightness of the RGB LEDs.
 *
 * @param led LED to set (1 or 2)
 * @param r Red intensity
 * @param g Green intensity
 * @param b Blue intensity
 */
void TiLDA_MKe::setLED(uint8_t led, uint8_t r, uint8_t g, uint8_t b)
{
  switch(led)
  {
    case 1:
      analogWrite(LED1_RED, r);
      analogWrite(LED1_GREEN, g);
      analogWrite(LED1_BLUE, b);
      break;
    case 2:
      analogWrite(LED2_RED, r);
      analogWrite(LED2_GREEN, g);
      analogWrite(LED2_BLUE, b);
      break;
    default:
      return;
  }
}

/**
 * Sets both RGB LEDs to the same colour.
 *
 * @param r Red intensity
 * @param g Green intensity
 * @param b Blue intensity
 */
void TiLDA_MKe::setLEDs(uint8_t r, uint8_t g, uint8_t b)
{
  setLED(1, r, g, b);
  setLED(2, r, g, b);
}

/**
 * Gets an approximation of the battery percentage.
 *
 * Note that the value is only accurate when not charging.
 *
 * @return Approx battery percentage
 */
uint8_t TiLDA_MKe::getBatteryPercentage()
{
  return (analogRead(VBATT_MON) - PMIC_BATTERY_FLAT) * PMIC_BATTERY_PERCENT_RATIO;
}

/**
 * Gets the battery voltage.
 *
 * @return Battery voltage
 */
float TiLDA_MKe::getBatteryVoltage()
{
  return (analogRead(VBATT_MON) * (3.3 / 512));
}

/**
 * Tests if the batter is being charged.
 *
 * @return True if charging, false otherwise
 */
bool TiLDA_MKe::isCharging()
{
  return !digitalRead(MCP_STAT);
}

/**
 * Prints a block of text in a given area, wrapping on a given character.
 *
 * @param x X coordinate of the top left corner of the area
 * @param y Y coordinate of the top left corner of the area
 * @param w Width of the area
 * @param h Height of the area
 * @param text Text string
 * @param delimiter Character to delimit text on
 */
void TiLDA_MKe::drawWrappedStr(uint8_t x, uint8_t y,
    uint8_t w, uint8_t h, char *text, char delimiter)
{
  char *last_newline_ptr = text;
  uint8_t y_increment = glcd.getFontLineSpacing();
  uint8_t pos_y = y + y_increment;

  while(*last_newline_ptr != '\0')
  {
    char *cut_point = getNewlinePtr(last_newline_ptr+1, w, delimiter);
    int16_t len = cut_point - last_newline_ptr;
    char *sub_str = new char[len + 1];

    char *copy_start = last_newline_ptr;
    if(*copy_start == delimiter)
      ++copy_start;

    memcpy(sub_str, copy_start, len);
    sub_str[len] = '\0';

    glcd.drawStr(x, pos_y, sub_str);

    delete[] sub_str;

    last_newline_ptr = cut_point;
    pos_y += y_increment;

    if(pos_y - y > h)
      return;
  }
}

/**
 * Determines if a string is too long to fit in a certain pixel width.
 *
 * @param string Pointer to the string
 * @param len Length of the sub string
 * @param limit Width in pixels the text must be less than
 * @return True if the substring is wider then limit
 */
bool TiLDA_MKe::subStringOverLength(char *string, uint8_t len, uint8_t limit)
{
  char *sub_str = new char[len + 1];
  memcpy(sub_str, string, len);
  sub_str[len] = '\0';
  uint8_t width = glcd.getStrWidth(sub_str);
  delete[] sub_str;
  return width > limit;
}

/**
 * Gets a pointer to the position to wrap text for the GLCD.
 *
 * @param string String pointer
 * @param width Max. text width in pixels
 * @param delimiter Char. to delimit text on
 * @return Pointer where the text should be split
 */
char *TiLDA_MKe::getNewlinePtr(char *string, uint8_t width, char delimiter)
{
  uint8_t len = 1;
  bool over_length = false;

  while(len < strlen(string))
  {
    if(subStringOverLength(string, len, width))
    {
      over_length = true;
      break;
    }
    len++;
  }

  if(over_length)
  {
    while(len > 0)
    {
      if(string[len] == delimiter)
        return string+len;

      len--;
    }
  }
  else
  {
    return string+len;
  }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <limits>
#include "consoleui.h"

using namespace std;

const char TAB = '\t';

ConsoleUI::ConsoleUI()
{

}

void ConsoleUI::WelcomeMenu()
{
    cout << endl;
    cout << endl;
    cout << TAB << "--------------------------------------------" << endl;
    cout << TAB << " Welcome! This program will store or show" << endl;
    cout << TAB << " famous computer scientists. " << endl;
    cout << TAB << "--------------------------------------------" << endl;
    cout << endl;
}

void ConsoleUI::features()
{
    cout << TAB << "----------------------------------------------------------------------------" << endl;
    cout << TAB << "The list below shows you all possible features on what you can do." << endl;
    cout << endl;
    cout << TAB << "press H to show all options" << endl; //eitthvað svona er sniðgt;
    cout << TAB << "Press 1 to create a new scientist." << endl;
    cout << TAB << "Press 2 to list all scientists." << endl;
    cout << TAB << "Press 3 to search for a scientist." << endl;
    cout << TAB << "Press Q to quit the program." << endl;
    cout << TAB << "----------------------------------------------------------------------------" << endl;
    cout << endl;
}
void ConsoleUI::readScientists()
{
    Scientist temp;

    string tempName;
    cout << TAB << "Please enter a name: ";
    cin.ignore(64,'\n');
    getline(cin, tempName);
    do
    {
        if(tempName.empty())
        {
            getline(cin, tempName);
            cout << TAB << "You cannot enter a empty name. Please try again: " << endl;
            getline(cin, tempName);
        }
    }
    while(tempName.empty());
    temp.setName(tempName);

    bool validGender = false;
    string tempGender;

    char gender;
    cout << TAB << "Please enter the gender(M for male, F for female): ";

        while(validGender == false)
        {
            cin >> gender;

            if(gender != 'M' && gender != 'm' && gender != 'F' && gender != 'f')
            {
                cout << TAB << gender << " That is not a valid option." << endl;
                cout << TAB <<" Please enter a valid option: " << endl;
            }
            if(gender == 'M'||gender=='m')
            {
                tempGender = "Male";
                temp.setGender(tempGender);
                validGender = true;
            }
            else if(gender == 'F'||gender == 'f')
            {
                tempGender = "Female";
                temp.setGender(tempGender);
                validGender = true;
            }
        }
            int tempDateOfBirth;
            int tempDateOfDeath;
            cout << TAB << "Please enter date of birth: ";

            do
            {
                cin >> tempDateOfBirth;
                if(tempDateOfBirth > 2016)
                {
                    cout << TAB << "Invalid date. Please try again: " << endl;
                }
                else if(tempDateOfBirth < 0)
                {
                    cout << TAB << "A person cannot have a negative date of birth. Please try again: ";
                }
                else if(!cin)
                {
                    while((!cin))
                    {
                    cin.clear();
                    cin.ignore(numeric_limits<streamsize>::max(),'\n');
                    cout << TAB << "That is not a date, please try again: " << endl;
                    cout << TAB << "Please enter date of birth: ";
                    cin >> tempDateOfBirth;
                    }
                }

            }
            while(tempDateOfBirth > 2016 || tempDateOfBirth < 0);

            temp.setDateOfBirth(tempDateOfBirth);

            cout << TAB << "Please enter a date of death(Enter 0 if the scientist is still alive): ";

            do
           {
                cin >> tempDateOfDeath;
                if(!cin)
                    {
                        while((!cin))
                        {
                        cin.clear();
                        cin.ignore(numeric_limits<streamsize>::max(),'\n');
                        cout << TAB << "Invalid date, that is not a year, try again:" << endl;
                        cout << TAB << "Please enter a date of death(Enter 0 if the scientist is still alive): ";
                        cin >> tempDateOfDeath;
                        }
                    }
                else if((tempDateOfDeath < tempDateOfBirth)&&(tempDateOfDeath != 0))
                {
                    cout << TAB << "Not possible. A person cannot die before it is born." << endl;
                    cout << TAB << "Please enter a date of death(Enter 0 if the scientist is still alive): ";
                    cin.clear();
                    cin >> tempDateOfDeath;
                }

            }
            while((tempDateOfDeath < tempDateOfBirth)&&(tempDateOfDeath != 0));

                if(tempDateOfDeath > 2016)
                {
                    cout << TAB << "Not possible. A person cannot die beyond the current year." << endl;
                }

            cout << endl;

            char cont;
            cout << TAB << "Do you want to add another scientist? Press Y/y for yes or N/n for no: ";
            cin >> cont;
            if(cont == 'y' || cont == 'Y')
            {
                readScientists();
            }
            else
            {
                features();
            }

    //flytur upplýsingar inn í ScientistService
    service.create(temp);
}

void ConsoleUI::display(vector<Scientist> scientists)
{
    cout << "\t Information about all listed scientists" << endl;
    cout << "\t___________________________________________________________________________" << endl;
    for(size_t i = 0; i < scientists.size(); i++)
    {
        cout << "\t |Name: " << scientists[i].getName() << endl;
        cout << "\t |Gender: " << scientists[i].getGender() << endl;
        cout << "\t |Born: " << scientists[i].getDateOfBirth() << endl;
        if(scientists[i].getDateOfDeath() == 0)
            cout << "\t |Still alive " << endl;
        else
            cout << "\t |Died: " << scientists[i].getDateOfDeath() << endl;
        cout << TAB << "----------------------------------------------------------------------------" << endl;
    }
}

void ConsoleUI::displayListOfScientistsAlpha()
{
    vector<Scientist> scientists = service.getScientistsAlpha();
    display(scientists);
}

void ConsoleUI::displayListOfScientistsYoung()
{
    vector<Scientist> scientists = service.getScientistsYoung();
    display(scientists);
}

void ConsoleUI::displayListOfScientistsOld()
{
    vector<Scientist> scientists = service.getScientistsOld();
    display(scientists);
}

void ConsoleUI::searchName()
{
     string name;
     cout << TAB << "Enter the name of the scientist you want to find: ";
     cin.ignore();
     getline(cin, name);

     vector<Scientist> temp = service.searchName(name);
     if(temp.size() == 0)
     {
         cout << TAB << "There is no scientist with the name " << name << " in our data, please try again: " << endl;
     }
     else
     {
         display(temp);
     }
}

void ConsoleUI::searchDateOfBirth()
{
    int year = 0;
    cout << TAB << "Enter the scientists year of birth: ";
    cin >> year;

    vector<Scientist> temp = service.searchDateOfBirth(year);
    if(temp.size() == 0)
    {
        cout << TAB << "There is no scientist in our database with that date of birth, please try again:" << endl;
    }
    else
    {
        display(temp);
    }
}

void ConsoleUI::searchGender()
{
    char gender;
    cout << TAB << "Please enter a gender(M for male, F for female): " << endl;

    cin >> gender;

    vector<Scientist> temp = service.searchGender(gender);
    if(temp.size() == 0)
    {
        if(gender == 'M' || gender == 'm')
        {
            cout << TAB << "There are no male scientists, try again:" << endl;
        }
        if(gender == 'F' || gender == 'f')
        {
            cout << TAB << "There are no female scientists, try again:" << endl;
        }
    }
    else
    {
        display(temp);
    }
}

void ConsoleUI::listOrSortScientist()
{
    string choice;

    while(choice != "q" && choice != "Q")
    {
        vector<Scientist> temp = service.getScientists();

        cout << TAB << "Please choose a feature: ";
        cin >> choice;
        cout << endl;

        if(choice == "h" || choice == "H")
        {
            features();
        }

        else if(choice == "1")
        {
            cout << TAB << ">>> Reading Scientists <<<" << endl << endl;
            readScientists();
        }

        else if(choice == "2")
        {
            int sort;
            cout << TAB << "How should the list be sorted?" << endl;
            cout << TAB << "Press 1 for alphabetical order." << endl;
            cout << TAB << "Press 2 to sort from youngest to oldest." << endl;
            cout << TAB << "Press 3 to sort from oldest to youngest." << endl;
            cout << TAB << "Press any other number to go BACK to the menu." << endl;
            cout << TAB << "" << endl;
            cout << TAB << "----------------------------------------------------------------------------" << endl;

            cin >> sort;

            if(sort == 1)
            {
                displayListOfScientistsAlpha();
            }
            if(sort == 2)
            {
                displayListOfScientistsYoung();
            }
            if(sort == 3)
            {
                displayListOfScientistsOld();
            }
        }

        else if(choice == "3")
        {
            int searchOptions = 0;

            cout << TAB << "What do you want to search for?" << endl;
            cout << TAB << "Press 1 to search for a scientist witch a specific name:" << endl;
            cout << TAB << "Press 2 to search for all scientists born in a specific year:" << endl;
            cout << TAB << "Press 3 to search for all scientists with a specific gender:" << endl;

            cout << TAB;
            cin >> searchOptions;

            if(searchOptions == 1)
            {
                searchName();
            }
            else if(searchOptions == 2)
            {
                searchDateOfBirth();
            }
            else if(searchOptions == 3)
            {
                searchGender();
            }
        }
    }
}

<commit_msg>laga sma i sort<commit_after>#include <iostream>
#include <string>
#include <limits>
#include "consoleui.h"

using namespace std;

const char TAB = '\t';

ConsoleUI::ConsoleUI()
{

}

void ConsoleUI::WelcomeMenu()
{
    cout << endl;
    cout << endl;
    cout << TAB << "--------------------------------------------" << endl;
    cout << TAB << " Welcome! This program will store or show" << endl;
    cout << TAB << " famous computer scientists. " << endl;
    cout << TAB << "--------------------------------------------" << endl;
    cout << endl;
}

void ConsoleUI::features()
{
    cout << TAB << "----------------------------------------------------------------------------" << endl;
    cout << TAB << "The list below shows you all possible features on what you can do." << endl;
    cout << endl;
    cout << TAB << "press H to show all options" << endl; //eitthvað svona er sniðgt;
    cout << TAB << "Press 1 to create a new scientist." << endl;
    cout << TAB << "Press 2 to list all scientists." << endl;
    cout << TAB << "Press 3 to search for a scientist." << endl;
    cout << TAB << "Press Q to quit the program." << endl;
    cout << TAB << "----------------------------------------------------------------------------" << endl;
    cout << endl;
}
void ConsoleUI::readScientists()
{
    Scientist temp;

    string tempName;
    cout << TAB << "Please enter a name: ";
    cin.ignore(64,'\n');
    getline(cin, tempName);
    do
    {
        if(tempName.empty())
        {
            getline(cin, tempName);
            cout << TAB << "You cannot enter a empty name. Please try again: " << endl;
            getline(cin, tempName);
        }
    }
    while(tempName.empty());
    temp.setName(tempName);

    bool validGender = false;
    string tempGender;

    char gender;
    cout << TAB << "Please enter the gender(M for male, F for female): ";

        while(validGender == false)
        {
            cin >> gender;

            if(gender != 'M' && gender != 'm' && gender != 'F' && gender != 'f')
            {
                cout << TAB << gender << " That is not a valid option." << endl;
                cout << TAB <<" Please enter a valid option: " << endl;
            }
            if(gender == 'M'||gender=='m')
            {
                tempGender = "Male";
                temp.setGender(tempGender);
                validGender = true;
            }
            else if(gender == 'F'||gender == 'f')
            {
                tempGender = "Female";
                temp.setGender(tempGender);
                validGender = true;
            }
        }
            int tempDateOfBirth;
            int tempDateOfDeath;
            cout << TAB << "Please enter date of birth: ";

            do
            {
                cin >> tempDateOfBirth;
                if(tempDateOfBirth > 2016)
                {
                    cout << TAB << "Invalid date. Please try again: " << endl;
                }
                else if(tempDateOfBirth < 0)
                {
                    cout << TAB << "A person cannot have a negative date of birth. Please try again: ";
                }
                else if(!cin)
                {
                    while((!cin))
                    {
                    cin.clear();
                    cin.ignore(numeric_limits<streamsize>::max(),'\n');
                    cout << TAB << "That is not a date, please try again: " << endl;
                    cout << TAB << "Please enter date of birth: ";
                    cin >> tempDateOfBirth;
                    }
                }

            }
            while(tempDateOfBirth > 2016 || tempDateOfBirth < 0);

            temp.setDateOfBirth(tempDateOfBirth);

            cout << TAB << "Please enter a date of death(Enter 0 if the scientist is still alive): ";

            do
           {
                cin >> tempDateOfDeath;
                if(!cin)
                    {
                        while((!cin))
                        {
                        cin.clear();
                        cin.ignore(numeric_limits<streamsize>::max(),'\n');
                        cout << TAB << "Invalid date, that is not a year, try again:" << endl;
                        cout << TAB << "Please enter a date of death(Enter 0 if the scientist is still alive): ";
                        cin >> tempDateOfDeath;
                        }
                    }
                else if((tempDateOfDeath < tempDateOfBirth)&&(tempDateOfDeath != 0))
                {
                    cout << TAB << "Not possible. A person cannot die before it is born." << endl;
                    cout << TAB << "Please enter a date of death(Enter 0 if the scientist is still alive): ";
                    cin.clear();
                    cin >> tempDateOfDeath;
                }

            }
            while((tempDateOfDeath < tempDateOfBirth)&&(tempDateOfDeath != 0));

                if(tempDateOfDeath > 2016)
                {
                    cout << TAB << "Not possible. A person cannot die beyond the current year." << endl;
                }

            cout << endl;

            char cont;
            cout << TAB << "Do you want to add another scientist? Press Y/y for yes or N/n for no: ";
            cin >> cont;
            if(cont == 'y' || cont == 'Y')
            {
                readScientists();
            }
            else
            {
                features();
            }

    //flytur upplýsingar inn í ScientistService
    service.create(temp);
}

void ConsoleUI::display(vector<Scientist> scientists)
{
    cout << "\t Information about all listed scientists" << endl;
    cout << "\t___________________________________________________________________________" << endl;
    for(size_t i = 0; i < scientists.size(); i++)
    {
        cout << "\t |Name: " << scientists[i].getName() << endl;
        cout << "\t |Gender: " << scientists[i].getGender() << endl;
        cout << "\t |Born: " << scientists[i].getDateOfBirth() << endl;
        if(scientists[i].getDateOfDeath() == 0)
            cout << "\t |Still alive " << endl;
        else
            cout << "\t |Died: " << scientists[i].getDateOfDeath() << endl;
        cout << TAB << "----------------------------------------------------------------------------" << endl;
    }
}

void ConsoleUI::displayListOfScientistsAlpha()
{
    vector<Scientist> scientists = service.getScientistsAlpha();
    display(scientists);
}

void ConsoleUI::displayListOfScientistsYoung()
{
    vector<Scientist> scientists = service.getScientistsYoung();
    display(scientists);
}

void ConsoleUI::displayListOfScientistsOld()
{
    vector<Scientist> scientists = service.getScientistsOld();
    display(scientists);
}

void ConsoleUI::searchName()
{
     string name;
     cout << TAB << "Enter the name of the scientist you want to find: ";
     cin.ignore();
     getline(cin, name);

     vector<Scientist> temp = service.searchName(name);
     if(temp.size() == 0)
     {
         cout << TAB << "There is no scientist with the name " << name << " in our data, please try again: " << endl;
     }
     else
     {
         display(temp);
     }
}

void ConsoleUI::searchDateOfBirth()
{
    int year = 0;
    cout << TAB << "Enter the scientists year of birth: ";
    cin >> year;

    vector<Scientist> temp = service.searchDateOfBirth(year);
    if(temp.size() == 0)
    {
        cout << TAB << "There is no scientist in our database with that date of birth, please try again:" << endl;
    }
    else
    {
        display(temp);
    }
}

void ConsoleUI::searchGender()
{
    char gender;
    cout << TAB << "Please enter a gender(M for male, F for female): " << endl;

    cin >> gender;

    vector<Scientist> temp = service.searchGender(gender);
    if(temp.size() == 0)
    {
        if(gender == 'M' || gender == 'm')
        {
            cout << TAB << "There are no male scientists, try again:" << endl;
        }
        if(gender == 'F' || gender == 'f')
        {
            cout << TAB << "There are no female scientists, try again:" << endl;
        }
    }
    else
    {
        display(temp);
    }
}

void ConsoleUI::listOrSortScientist()
{
    string choice;

    while(choice != "q" && choice != "Q")
    {
        vector<Scientist> temp = service.getScientists();

        cout << TAB << "Please choose a feature: ";
        cin >> choice;
        cout << endl;

        if(choice == "h" || choice == "H")
        {
            features();
        }

        else if(choice == "1")
        {
            cout << TAB << ">>> Reading Scientists <<<" << endl << endl;
            readScientists();
        }

        else if(choice == "2")
        {
            string sort;
            cout << TAB << "How should the list be sorted?" << endl;
            cout << TAB << "Press 1 for alphabetical order." << endl;
            cout << TAB << "Press 2 to sort from youngest to oldest." << endl;
            cout << TAB << "Press 3 to sort from oldest to youngest." << endl;
            cout << TAB << "Press any other number to go BACK to the menu." << endl;
            cout << TAB << "" << endl;
            cout << TAB << "----------------------------------------------------------------------------" << endl;
            cout << TAB;

            cin >> sort;
            if(sort == "1")
            {
                displayListOfScientistsAlpha();
            }
            else if(sort == "2")
            {
                displayListOfScientistsYoung();
            }
            else if(sort == "3")
            {
                displayListOfScientistsOld();
            }
            else
            {
                features();
            }
        }

        else if(choice == "3")
        {
            int searchOptions = 0;

            cout << TAB << "What do you want to search for?" << endl;
            cout << TAB << "Press 1 to search for a scientist witch a specific name:" << endl;
            cout << TAB << "Press 2 to search for all scientists born in a specific year:" << endl;
            cout << TAB << "Press 3 to search for all scientists with a specific gender:" << endl;

            cout << TAB;
            cin >> searchOptions;

            if(searchOptions == 1)
            {
                searchName();
            }
            else if(searchOptions == 2)
            {
                searchDateOfBirth();
            }
            else if(searchOptions == 3)
            {
                searchGender();
            }
        }
    }
}

<|endoftext|>


<commit_before>#include "sample.h"
#include <gtest/gtest.h>

TEST(FactorialTest, Zero) {
    EXPECT_EQ(1, Factorial(0));
}
<commit_msg>Broke down our unit tests into gtest functions<commit_after>#include "sample.h"
#include <gtest/gtest.h>

/* First sample Test */
TEST(FactorialTest, Zero) {
    EXPECT_EQ(1, Factorial(0));
}

/* Building 1st Event Log */
TEST(BuildingEventLog, one) {
   EXPECT_EQ(1, 1);
}

/* Building 2nd Event Log */
TEST(BuildingEventLog, two) {
   EXPECT_EQ(1, 1);
}

/* Read Log 1 */
TEST(ReadLog, one) {
   EXPECT_EQ(1, 1);
}

/* Read Log 2 */
TEST(ReadLog, two) {
   EXPECT_EQ(1, 1);
}

/* Lets delete the earlier log, then create a new event manager
   the latest_log_id should still be 2 */
TEST(DeleteEarlierLog, one) {
   EXPECT_EQ(1, 1);
}

/* Travese log list stuff */
TEST(TraverseLogList, one) {
   EXPECT_EQ(1, 1);
}

/* Testing the max limits for event logs */
TEST(TestMaxLimitLogs, one) {
   EXPECT_EQ(1, 1);
}

/* Testing the max limits for event logs */
TEST(TestMaxLimitLogs, two) {
   EXPECT_EQ(1, 1);
}

/* Create an abundence of logs, then restart with a limited set  */
/* You should not be able to create new logs until the log size  */
/* dips below the request number                                 */
TEST(CreateLogsRestartSet, one) {
   EXPECT_EQ(1, 1);
}

/* Delete logs to dip below the requested limit */
TEST(DeleteLogsBelowLimit, one) {
   EXPECT_EQ(1, 1);
}

/* Create an abundence of logs, then restart with a limited set  */
/* You should not be able to create new logs until the log size  */
/* dips below the request number                                 */
TEST(CreateLogsRestartSet, two) {
   EXPECT_EQ(1, 1);
}

//Run all the tests that were declared with TEST()
int main(int argc, char **argv)
{
   testing::InitGoogleTest(&argc, argv);
   return RUN_ALL_TESTS();
}

<|endoftext|>


<commit_before>// This file is part of Poseidon.
// Copyleft 2022, LH_Mouse. All wrongs reserved.

#ifndef POSEIDON_TEST_UTILS_
#define POSEIDON_TEST_UTILS_

#include "../src/fwd.hpp"
#include "../src/utils.hpp"
#include <unistd.h>   // ::alarm()

#define POSEIDON_TEST_CHECK(expr)  \
    do  \
      try {  \
        if(static_cast<bool>(expr) == false) {  \
          /* failed */  \
          ::asteria::write_log_to_stderr(__FILE__, __LINE__, __func__,  \
              ::rocket::sref("POSEIDON_TEST_CHECK FAIL: " #expr));  \
          \
          ::abort();  \
        }  \
        \
        /* successful */  \
        ::asteria::write_log_to_stderr(__FILE__, __LINE__, __func__,  \
            ::rocket::sref("POSEIDON_TEST_CHECK PASS: " #expr));  \
      }  \
      catch(exception& stdex) {  \
        /* failed */  \
        ::asteria::write_log_to_stderr(__FILE__, __LINE__, __func__,  \
            ::rocket::cow_string("POSEIDON_TEST_CHECK EXCEPTION: " #expr)  \
              + "\n" + stdex.what());  \
        \
        ::abort();  \
      }  \
    while(false)

#define POSEIDON_TEST_CHECK_CATCH(expr)  \
    do  \
      try {  \
        (void) (expr);  \
        \
        /* failed */  \
        ::asteria::write_log_to_stderr(__FILE__, __LINE__, __func__,  \
            ::rocket::sref("POSEIDON_TEST_CHECK XPASS: " #expr));  \
        \
        ::abort();  \
      }  \
      catch(::std::exception& stdex) {  \
        /* successful */  \
        ::asteria::write_log_to_stderr(__FILE__, __LINE__, __func__,  \
            ::rocket::cow_string("POSEIDON_TEST_CHECK XFAIL: " #expr)  \
              + "\n" + stdex.what());  \
      }  \
    while(false)

// Set terminate handler.
static const auto poseidon_test_terminate = ::std::set_terminate(
    [] {
      auto eptr = ::std::current_exception();
      if(eptr) {
        try {
          ::std::rethrow_exception(eptr);
        }
        catch(::std::exception& stdex) {
          ::fprintf(stderr,
              "`::std::terminate()` called after `::std::exception`:\n%s\n",
              stdex.what());
        }
        catch(...) {
          ::fprintf(stderr,
              "`::std::terminate()` called after an unknown exception\n");
        }
      }
      else
        ::fprintf(stderr,
            "`::std::terminate()` called without an exception\n");

      ::fflush(nullptr);
      ::_Exit(1);
    });

// Set kill timer.
static const auto poseidon_test_alarm = ::alarm(30);

#endif
<commit_msg>test: Use qualified names for `::std::exception`<commit_after>// This file is part of Poseidon.
// Copyleft 2022, LH_Mouse. All wrongs reserved.

#ifndef POSEIDON_TEST_UTILS_
#define POSEIDON_TEST_UTILS_

#include "../src/fwd.hpp"
#include "../src/utils.hpp"
#include <unistd.h>   // ::alarm()

#define POSEIDON_TEST_CHECK(expr)  \
    do  \
      try {  \
        if(static_cast<bool>(expr) == false) {  \
          /* failed */  \
          ::asteria::write_log_to_stderr(__FILE__, __LINE__, __func__,  \
              ::rocket::sref("POSEIDON_TEST_CHECK FAIL: " #expr));  \
          \
          ::abort();  \
        }  \
        \
        /* successful */  \
        ::asteria::write_log_to_stderr(__FILE__, __LINE__, __func__,  \
            ::rocket::sref("POSEIDON_TEST_CHECK PASS: " #expr));  \
      }  \
      catch(::std::exception& stdex) {  \
        /* failed */  \
        ::asteria::write_log_to_stderr(__FILE__, __LINE__, __func__,  \
            ::rocket::cow_string("POSEIDON_TEST_CHECK EXCEPTION: " #expr)  \
              + "\n" + stdex.what());  \
        \
        ::abort();  \
      }  \
    while(false)

#define POSEIDON_TEST_CHECK_CATCH(expr)  \
    do  \
      try {  \
        (void) (expr);  \
        \
        /* failed */  \
        ::asteria::write_log_to_stderr(__FILE__, __LINE__, __func__,  \
            ::rocket::sref("POSEIDON_TEST_CHECK XPASS: " #expr));  \
        \
        ::abort();  \
      }  \
      catch(::std::exception& stdex) {  \
        /* successful */  \
        ::asteria::write_log_to_stderr(__FILE__, __LINE__, __func__,  \
            ::rocket::cow_string("POSEIDON_TEST_CHECK XFAIL: " #expr)  \
              + "\n" + stdex.what());  \
      }  \
    while(false)

// Set terminate handler.
static const auto poseidon_test_terminate = ::std::set_terminate(
    [] {
      auto eptr = ::std::current_exception();
      if(eptr) {
        try {
          ::std::rethrow_exception(eptr);
        }
        catch(::std::exception& stdex) {
          ::fprintf(stderr,
              "`::std::terminate()` called after `::std::exception`:\n%s\n",
              stdex.what());
        }
        catch(...) {
          ::fprintf(stderr,
              "`::std::terminate()` called after an unknown exception\n");
        }
      }
      else
        ::fprintf(stderr,
            "`::std::terminate()` called without an exception\n");

      ::fflush(nullptr);
      ::_Exit(1);
    });

// Set kill timer.
static const auto poseidon_test_alarm = ::alarm(30);

#endif
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "helpers.h"
#include "render_to_window.h"

static VkBool32 debug_report_callback(
    VkDebugUtilsMessageSeverityFlagBitsEXT           messageSeverity,
    VkDebugUtilsMessageTypeFlagsEXT                  messageTypes,
    const VkDebugUtilsMessengerCallbackDataEXT*      pCallbackData,
    void*                                            pUserData)
{
    std::cerr << pCallbackData->pMessage << std::endl;
    return false;
}

static std::optional<vk::UniqueDebugUtilsMessengerEXT> create_debug_report_callback(vk::Instance instance)
{
#if _DEBUG
    auto info = vk::DebugUtilsMessengerCreateInfoEXT()
        .setMessageSeverity(
            vk::DebugUtilsMessageSeverityFlagBitsEXT::eError|
            vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning
        )
        .setMessageType(
            vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral|
            vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance|
            vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation
        )
    .setPfnUserCallback(debug_report_callback);

    return std::optional { instance.createDebugUtilsMessengerEXTUnique(info, nullptr) };
#else
    return std::nullopt;
#endif
}

static vk::UniqueInstance create_instance()
{
#if _DEBUG
    std::array layerNames { "VK_LAYER_KHRONOS_validation" };
#else
    std::array<const char*, 0> layerNames;
#endif

    std::array extensionNames {
#if _DEBUG
        VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
#endif
        VK_KHR_SURFACE_EXTENSION_NAME,
        VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
        VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
    };

    return vk::createInstanceUnique(
        vk::InstanceCreateInfo()
        .setPEnabledLayerNames(layerNames)
        .setPEnabledExtensionNames(extensionNames)
    );
}

static vk::PhysicalDevice get_physical_device(vk::Instance vulkan)
{
    auto devices = vulkan.enumeratePhysicalDevices();
    assert(devices.size() > 0);

    auto device = devices[0];
    auto props = device.getProperties();
    std::cout << "Using physical device " << props.deviceName << std::endl;
    return device;
}

static vk::UniqueDevice create_device(vk::PhysicalDevice physical_device)
{
    auto props = physical_device.getQueueFamilyProperties();
    assert((props[0].queueFlags & vk::QueueFlagBits::eGraphics) == vk::QueueFlagBits::eGraphics);

    std::array priorities { 0.f };
    auto queueInfo = vk::DeviceQueueCreateInfo()
        .setQueuePriorities(priorities);

    std::array extensionNames {
        VK_KHR_SWAPCHAIN_EXTENSION_NAME,
        VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
        VK_NV_RAY_TRACING_EXTENSION_NAME,
    };

    auto features = vk::PhysicalDeviceFeatures()
        .setMultiDrawIndirect(true)
        .setDrawIndirectFirstInstance(true)
        .setShaderClipDistance(true)
        .setShaderCullDistance(true);

    return physical_device.createDeviceUnique(
        vk::DeviceCreateInfo()
        .setQueueCreateInfoCount(1)
        .setPQueueCreateInfos(&queueInfo)
        .setPEnabledExtensionNames(extensionNames)
        .setPEnabledFeatures(&features)
    );
}

glm::vec3 std_vector_to_glm_vec3(const std::vector<float>& vector)
{
    return glm::vec3(vector[0], vector[1], vector[2]);
}

VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE

int main(int argc, char** argv)
{
    cxxopts::Options options("VulkanRenderer", "Vulkan renderer");
    options.add_options()
        ("model", "PLY model to render. File dialog will be shown if ommitted.", cxxopts::value<std::string>(), "path")
        ("image", "PNG image to save rendering to (overwrites existing). No window will be created if specified.", cxxopts::value<std::string>(), "path")
        ("camera_position", "When using --image, specifies the camera position.", cxxopts::value<std::vector<float>>(), "x y z")
        ("camera_up", "When using --image, specifies the camera up vector.", cxxopts::value<std::vector<float>>(), "x y z")
        ("help", "Show help")
        ;

    cxxopts::ParseResult result = options.parse(argc, argv);

    if (result["help"].count() > 0) {
        std::cout << options.help();
        return EXIT_SUCCESS;
    }

    std::string model_path;
    auto model_path_option = result["model"];

    if (model_path_option.count() == 1)
    {
        model_path = model_path_option.as<std::string>();
    }
    else
    {
        auto pattern = "*.ply";
        auto model_path_ptr = tinyfd_openFileDialog("Open 3D model", nullptr, 1, &pattern, nullptr, 0);
        if (!model_path_ptr)
        {
            return EXIT_FAILURE;
        }
        model_path = model_path_ptr;
    }

    vk::DynamicLoader dl;
    VULKAN_HPP_DEFAULT_DISPATCHER.init(dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"));

    auto instance = create_instance();
    VULKAN_HPP_DEFAULT_DISPATCHER.init(instance.get());

    auto callback = create_debug_report_callback(instance.get());
    auto physical_device = get_physical_device(instance.get());

    auto device = create_device(physical_device);
    VULKAN_HPP_DEFAULT_DISPATCHER.init(device.get());

    auto image_path_option = result["image"];
    if (image_path_option.count() == 1)
    {
        auto camera_position_option = result["camera_position"];
        auto camera_position = camera_position_option.count() == 3
            ? std_vector_to_glm_vec3(camera_position_option.as<std::vector<float>>())
            : glm::vec3(0.f, 0.f, 2.f);

        auto camera_up_vector = result["camera_up"];
        auto camera_up = camera_up_vector.count() == 3
            ? std_vector_to_glm_vec3(camera_up_vector.as<std::vector<float>>())
            : glm::vec3(0.f, -1.f, 0.f);

        std::cout << "Rendering to image..." << std::endl;
        render_to_image(physical_device, device.get(), model_path, image_path_option.as<std::string>(), camera_position, camera_up);
    }
    else
    {
        std::cout << "Rendering to window..." << std::endl;
        render_to_window(instance.get(), physical_device, device.get(), model_path);
    }

    return EXIT_SUCCESS;
}
<commit_msg>Set Vulkan version to 1.1<commit_after>#include "stdafx.h"
#include "helpers.h"
#include "render_to_window.h"

static VkBool32 debug_report_callback(
    VkDebugUtilsMessageSeverityFlagBitsEXT           messageSeverity,
    VkDebugUtilsMessageTypeFlagsEXT                  messageTypes,
    const VkDebugUtilsMessengerCallbackDataEXT*      pCallbackData,
    void*                                            pUserData)
{
    std::cerr << pCallbackData->pMessage << std::endl;
    return false;
}

static std::optional<vk::UniqueDebugUtilsMessengerEXT> create_debug_report_callback(vk::Instance instance)
{
#if _DEBUG
    auto info = vk::DebugUtilsMessengerCreateInfoEXT()
        .setMessageSeverity(
            vk::DebugUtilsMessageSeverityFlagBitsEXT::eError|
            vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning
        )
        .setMessageType(
            vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral|
            vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance|
            vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation
        )
    .setPfnUserCallback(debug_report_callback);

    return std::optional { instance.createDebugUtilsMessengerEXTUnique(info, nullptr) };
#else
    return std::nullopt;
#endif
}

static vk::UniqueInstance create_instance()
{
#if _DEBUG
    std::array layerNames { "VK_LAYER_KHRONOS_validation" };
#else
    std::array<const char*, 0> layerNames;
#endif

    std::array extensionNames {
#if _DEBUG
        VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
#endif
        VK_KHR_SURFACE_EXTENSION_NAME,
        VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
        VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
    };

    auto app_info = vk::ApplicationInfo().setApiVersion(VK_API_VERSION_1_1);

    return vk::createInstanceUnique(
        vk::InstanceCreateInfo()
        .setPEnabledLayerNames(layerNames)
        .setPEnabledExtensionNames(extensionNames)
        .setPApplicationInfo(&app_info)
    );
}

static vk::PhysicalDevice get_physical_device(vk::Instance vulkan)
{
    auto devices = vulkan.enumeratePhysicalDevices();
    assert(devices.size() > 0);

    auto device = devices[0];
    auto props = device.getProperties();
    std::cout << "Using physical device " << props.deviceName << std::endl;
    return device;
}

static vk::UniqueDevice create_device(vk::PhysicalDevice physical_device)
{
    auto props = physical_device.getQueueFamilyProperties();
    assert((props[0].queueFlags & vk::QueueFlagBits::eGraphics) == vk::QueueFlagBits::eGraphics);

    std::array priorities { 0.f };
    auto queueInfo = vk::DeviceQueueCreateInfo()
        .setQueuePriorities(priorities);

    std::array extensionNames {
        VK_KHR_SWAPCHAIN_EXTENSION_NAME,
        VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
        VK_NV_RAY_TRACING_EXTENSION_NAME,
    };

    auto features = vk::PhysicalDeviceFeatures()
        .setMultiDrawIndirect(true)
        .setDrawIndirectFirstInstance(true)
        .setShaderClipDistance(true)
        .setShaderCullDistance(true);

    return physical_device.createDeviceUnique(
        vk::DeviceCreateInfo()
        .setQueueCreateInfoCount(1)
        .setPQueueCreateInfos(&queueInfo)
        .setPEnabledExtensionNames(extensionNames)
        .setPEnabledFeatures(&features)
    );
}

glm::vec3 std_vector_to_glm_vec3(const std::vector<float>& vector)
{
    return glm::vec3(vector[0], vector[1], vector[2]);
}

VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE

int main(int argc, char** argv)
{
    cxxopts::Options options("VulkanRenderer", "Vulkan renderer");
    options.add_options()
        ("model", "PLY model to render. File dialog will be shown if ommitted.", cxxopts::value<std::string>(), "path")
        ("image", "PNG image to save rendering to (overwrites existing). No window will be created if specified.", cxxopts::value<std::string>(), "path")
        ("camera_position", "When using --image, specifies the camera position.", cxxopts::value<std::vector<float>>(), "x y z")
        ("camera_up", "When using --image, specifies the camera up vector.", cxxopts::value<std::vector<float>>(), "x y z")
        ("help", "Show help")
        ;

    cxxopts::ParseResult result = options.parse(argc, argv);

    if (result["help"].count() > 0) {
        std::cout << options.help();
        return EXIT_SUCCESS;
    }

    std::string model_path;
    auto model_path_option = result["model"];

    if (model_path_option.count() == 1)
    {
        model_path = model_path_option.as<std::string>();
    }
    else
    {
        auto pattern = "*.ply";
        auto model_path_ptr = tinyfd_openFileDialog("Open 3D model", nullptr, 1, &pattern, nullptr, 0);
        if (!model_path_ptr)
        {
            return EXIT_FAILURE;
        }
        model_path = model_path_ptr;
    }

    vk::DynamicLoader dl;
    VULKAN_HPP_DEFAULT_DISPATCHER.init(dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"));

    auto instance = create_instance();
    VULKAN_HPP_DEFAULT_DISPATCHER.init(instance.get());

    auto callback = create_debug_report_callback(instance.get());
    auto physical_device = get_physical_device(instance.get());

    auto device = create_device(physical_device);
    VULKAN_HPP_DEFAULT_DISPATCHER.init(device.get());

    auto image_path_option = result["image"];
    if (image_path_option.count() == 1)
    {
        auto camera_position_option = result["camera_position"];
        auto camera_position = camera_position_option.count() == 3
            ? std_vector_to_glm_vec3(camera_position_option.as<std::vector<float>>())
            : glm::vec3(0.f, 0.f, 2.f);

        auto camera_up_vector = result["camera_up"];
        auto camera_up = camera_up_vector.count() == 3
            ? std_vector_to_glm_vec3(camera_up_vector.as<std::vector<float>>())
            : glm::vec3(0.f, -1.f, 0.f);

        std::cout << "Rendering to image..." << std::endl;
        render_to_image(physical_device, device.get(), model_path, image_path_option.as<std::string>(), camera_position, camera_up);
    }
    else
    {
        std::cout << "Rendering to window..." << std::endl;
        render_to_window(instance.get(), physical_device, device.get(), model_path);
    }

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include <istream>
#include <utility>
#include <sstream>
#include <cstdlib>

#include "number.hh"

using namespace std;

namespace {

enum class Exactness{
  exact, inexact, unspecified
    };

pair<int, Exactness> parse_number_prefix(std::istream& i){
  static const auto to_radix = [](char c){
    return (c == 'b') ? 2
    : (c == 'o') ? 8
    : (c == 'd') ? 10
    : (c == 'x') ? 16
    : -1;
  };

  static const auto to_exactness = [](char c){
    return (c == 'i') ? Exactness::inexact
    : (c == 'e') ? Exactness::exact
    : Exactness::unspecified;
  };

  int r = 10;
  Exactness e = Exactness::unspecified;
  bool r_appeared = false, e_appeared = false;

  for(int loop = 0; loop < 2; ++loop){
    if(i.peek() != '#')
      return {r, e};
    i.ignore(1);

    switch(auto c = i.get()){
    case 'i': case 'e':
      if(e_appeared) goto error;
      e = to_exactness(c);
      e_appeared = true;
      break;
    case 'b': case 'o': case 'd': case 'x':
      if(r_appeared) goto error;
      r = to_radix(c);
      r_appeared = true;
      break;
    default:
      goto error;
    }
  }

  return {r, e};

 error:
  return {-1, Exactness::unspecified};
}

inline
bool is_number_char(int radix, char c){
  switch(radix){
  case 16:
  switch(c){
  case 'a': case 'A': case 'b': case 'B':
  case 'c': case 'C': case 'd': case 'D':
  case 'e': case 'E': case 'f': case 'F':
    return true;
  }

  case 10:
  switch(c){
  case '8': case '9':
    return true;
  }

  case 8:
  switch(c){
  case '2': case '3': case '4':
  case '5': case '6': case '7':
    return true;
  }

  case 2:
    switch(c){
    case '0': case '1':
      return true;
    }

    return false;

  default:
    UNEXP_DEFAULT();
  }
}

template<typename IN, typename OUT>
inline
int eat_sharp(IN& i, OUT& o){
  int sharps = 0;

  while(i.peek() == '#'){
    i.ignore(1);
    o.put('0');
    ++sharps;
  }

  return sharps;
}

typedef pair<Number, Exactness> ParserRet;

#define PARSE_ERROR_VALUE (ParserRet{{}, Exactness::unspecified})

ParserRet parse_unsigned(int radix, std::istream& i, stringstream& s){
  while(is_number_char(radix, i.peek()))
    s.put(i.get());

  if(s.str().empty()){
    goto error;
  }else{
    Exactness e;

    if(eat_sharp(i, s) > 0){
      e = Exactness::inexact;
    }else{
      e = Exactness::exact;
    }

    errno = 0;
    long l = strtol(s.str().c_str(), nullptr, radix);
    if(errno) goto error;

    return {Number{l}, e};
  }

 error:
  return PARSE_ERROR_VALUE;
}

inline
bool check_decimal_suffix(char c){
  switch(c){
  case 'e': case 's': case 'f': case 'd': case 'l':
    return true;
  default:
    return false;
  }
}

ParserRet parse_decimal(std::istream& i, stringstream& s){
  bool dot_start = false;
  int sharps_before_dot = 0;

  if(s.str().empty()){
    if(i.peek() == '.'){
      dot_start = true;
    }else{
      goto error;
    }
  }else{
    sharps_before_dot = eat_sharp(i, s);
  }

  if(i.peek() != '.'){
    goto end; // 1. no frac part
  }
  s.put(i.get());

  if(sharps_before_dot > 0){
    eat_sharp(i, s);
    goto end; // 4. only sharps after dot
  }

  if(dot_start && !is_number_char(10, i.peek()))
    goto error; // 2. dot start should have digits

  while(is_number_char(10, i.peek())){
    s.put(i.get());
  }

  eat_sharp(i, s);

 end:
  if(check_decimal_suffix(i.peek())){
    i.ignore(1);
    s.put('e');

    switch(i.peek()){
    case '+': case '-':
      s.put(i.get());
    }

    if(!is_number_char(10, i.peek())){
      goto error; // no number on exp. part
    }

    while(is_number_char(10, i.peek())){
      s.put(i.get());
    }
  }

  return {Number{strtod(s.str().c_str(), nullptr)},
      Exactness::inexact};

 error:
  return PARSE_ERROR_VALUE;
}

ParserRet parse_real_number(int radix, std::istream& i){
  int sign = 1;

  switch(i.peek()){
  case '+':
    sign = 1;
    i.ignore(1);
    break;
  case '-':
    sign = -1;
    i.ignore(1);
    break;
  default:
    sign = 1;
    break;
  }

  stringstream s;

  auto u1 = parse_unsigned(radix, i, s);
  if(!get<0>(u1)){
    if(i.peek() == '.'){
      goto decimal_float_check;
    }else{
      goto error;
    }
  }

  if(check_decimal_suffix(i.peek()) || i.peek() == '.'){
  decimal_float_check:
    if(radix == 10){
      auto n = parse_decimal(i, s);

      if(get<0>(n).type() == Number::Type::real){
        return {Number{get<0>(n).get<double>() * sign},
            Exactness::inexact};
      }
    }
    goto error;
  }

  if(i.peek() != '/'){ // integer?
    // FIXME: inexact or super-big integer can be fall into float.
    return {Number(sign * get<0>(u1).get<long>()), get<1>(u1)};
  }else{
    // rational
    stringstream s2;
    auto u2 = parse_unsigned(radix, i, s2);
    if(!get<0>(u2))
      goto error;
    return {Number(sign * get<0>(u1).get<double>() / get<0>(u2).get<double>()),
        Exactness::inexact};
  }

 error:
  return PARSE_ERROR_VALUE;
}

ParserRet parse_complex(int radix, std::istream& i){
  const auto first_char = i.peek();

  // has real part
  auto real = parse_real_number(radix, i);
  if(!get<0>(real))
    goto error;

  switch(auto c = i.peek()){
  case '@': {// polar literal
    i.ignore(1);
    auto deg = parse_real_number(radix, i);

    if(!get<0>(deg))
      goto error;

    return {Number{polar(get<0>(real).get<double>(), get<0>(deg).get<double>())},
        Exactness::inexact};
  }
  case '+': case '-': {
    i.ignore(1);
    const int sign = (c == '+') ? 1 : -1;

    if(i.peek() == 'i'){
      i.ignore(1);
      return {Number{get<0>(real).get<double>(), static_cast<double>(sign)},
          Exactness::inexact};
    }

    auto imag = parse_real_number(radix, i);
    if(!get<0>(imag) || i.get() != 'i')
      goto error;

    return {Number{get<0>(real).get<double>(), get<0>(imag).get<double>() * sign},
        Exactness::inexact};
  }
  case 'i':
    i.ignore(1);
    if(first_char == '+' || first_char == '-'){
      return {Number{0, get<0>(real).get<double>()},
          Exactness::inexact};
    }else{
      goto error;
    }
  default:
    return real;
  }

 error:
  return PARSE_ERROR_VALUE;
}

} // namespace

Number parse_number(std::istream& i){
  const auto prefix_info = parse_number_prefix(i);

  ParserRet r;

  switch(auto radix = get<0>(prefix_info)){
  case 2: case 8: case 10: case 16:
    r = parse_complex(radix, i);
    break;
  default:
    goto error;
  }

  if(!get<0>(r)) goto error;

  // TODO: check inexact integer, and warn.

  switch(auto e = get<1>(prefix_info)){
  case Exactness::exact:
    return (get<1>(r) == e) ? get<0>(r) : to_exact(get<0>(r));
  case Exactness::inexact:
    return (get<1>(r) == e) ? get<0>(r) : to_inexact(get<0>(r));
  case Exactness::unspecified:
    return get<0>(r);
  default:
    goto error;
  }

 error:
  return {};
}

bool eql(const Number& n, const Number& m){
  if(n.type() != m.type()) return false;

  switch(n.type()){
  case Number::Type::uninitialized:
    return false;
  case Number::Type::complex:
    return n.get<Number::complex_type>() == m.get<Number::complex_type>();
  case Number::Type::real:
    return n.get<Number::real_type>() == m.get<Number::real_type>();
  case Number::Type::integer:
    return n.get<Number::integer_type>() == m.get<Number::integer_type>();
  default:
    UNEXP_DEFAULT();
  }
}

void print(FILE* f, const Number& n){
  switch(n.type()){
  case Number::Type::uninitialized:
    fprintf(f, "(uninitialied number)");
    break;
  case Number::Type::complex: {
    auto&& z = n.get<Number::complex_type>();
    fprintf(f, "%g+%gi", z.real(), z.imag());
  }
    break;
  case Number::Type::real:
    fprintf(f, "%g", n.get<Number::real_type>());
    break;
  case Number::Type::integer:
    fprintf(f, "%ld", n.get<Number::integer_type>());
    break;
  default:
    UNEXP_DEFAULT();
  }
}

Number to_exact(const Number& n){
  switch(n.type()){
  case Number::Type::complex:
    return {}; // not supported
  case Number::Type::real:
    return {}; // not supported
  case Number::Type::integer:
    return n;
  case Number::Type::uninitialized:
  default:
    return {};
  }
}

Number to_inexact(const Number& n){
  switch(n.type()){
  case Number::Type::complex:
    return n;
  case Number::Type::real:
    return n;
  case Number::Type::integer:
    return Number{static_cast<Number::real_type>
        (n.get<Number::integer_type>())};
  case Number::Type::uninitialized:
  default:
    return {};
  }
}

const char* stringify(Number::Type t){
  switch(t){
  case Number::Type::uninitialized:
    return "uninitialized";
  case Number::Type::complex:
    return "complex";
  case Number::Type::real:
    return "real";
  case Number::Type::integer:
    return "integer";
  default:
    return "(unknown number type)";
  }
}

void describe(FILE* f, Number::Type t){
  fputs(stringify(t), f);
}

void describe(FILE* f, const Number& n){
  const auto t = n.type();

  fprintf(f, "Number: %s(", stringify(t));

  switch(t){
  case Number::Type::uninitialized:
    break;
  case Number::Type::complex: {
    const auto& z = n.get<Number::complex_type>();
    fprintf(f, "%g+%gi", z.real(), z.imag());
  }
    break;
  case Number::Type::real:
    fprintf(f, "%g", n.get<Number::real_type>());
    break;
  case Number::Type::integer:
    fprintf(f, "%ld", n.get<Number::integer_type>());
    break;
  default:
    break;
  }

  fputc(')', f);
}

<commit_msg>cleanup number parser<commit_after>#include <istream>
#include <utility>
#include <sstream>
#include <cstdlib>

#include "number.hh"

using namespace std;

namespace {

enum class Exactness{
  exact, inexact, unspecified
    };

pair<int, Exactness> parse_number_prefix(std::istream& i){
  static const auto to_radix = [](char c){
    return (c == 'b') ? 2
    : (c == 'o') ? 8
    : (c == 'd') ? 10
    : (c == 'x') ? 16
    : -1;
  };

  static const auto to_exactness = [](char c){
    return (c == 'i') ? Exactness::inexact
    : (c == 'e') ? Exactness::exact
    : Exactness::unspecified;
  };

  int r = 10;
  Exactness e = Exactness::unspecified;
  bool r_appeared = false, e_appeared = false;

  for(int loop = 0; loop < 2; ++loop){
    if(i.peek() != '#')
      return {r, e};
    i.ignore(1);

    switch(auto c = i.get()){
    case 'i': case 'e':
      if(e_appeared) goto error;
      e = to_exactness(c);
      e_appeared = true;
      break;
    case 'b': case 'o': case 'd': case 'x':
      if(r_appeared) goto error;
      r = to_radix(c);
      r_appeared = true;
      break;
    default:
      goto error;
    }
  }

  return {r, e};

 error:
  return {-1, Exactness::unspecified};
}

inline
bool is_number_char(int radix, char c){
  switch(radix){
  case 16:
    return isxdigit(c);

  case 10:
    return isdigit(c);

  case 8:
    switch(c){
    case '0': case '1':
    case '2': case '3': case '4':
    case '5': case '6': case '7':
      return true;
    default:
      return false;
    }

  case 2:
    switch(c){
    case '0': case '1':
      return true;
    default:
      return false;
    }

  default:
    UNEXP_DEFAULT();
  }
}

template<typename IN, typename OUT>
inline
int eat_sharp(IN& i, OUT& o){
  int sharps = 0;

  while(i.peek() == '#'){
    i.ignore(1);
    o.put('0');
    ++sharps;
  }

  return sharps;
}

typedef pair<Number, Exactness> ParserRet;

#define PARSE_ERROR_VALUE (ParserRet{{}, Exactness::unspecified})

ParserRet parse_unsigned(int radix, std::istream& i, stringstream& s){
  while(is_number_char(radix, i.peek()))
    s.put(i.get());

  if(s.str().empty()){
    goto error;
  }else{
    Exactness e;

    if(eat_sharp(i, s) > 0){
      e = Exactness::inexact;
    }else{
      e = Exactness::exact;
    }

    errno = 0;
    long l = strtol(s.str().c_str(), nullptr, radix);
    if(errno) goto error;

    return {Number{l}, e};
  }

 error:
  return PARSE_ERROR_VALUE;
}

inline
bool check_decimal_suffix(char c){
  switch(c){
  case 'e': case 's': case 'f': case 'd': case 'l':
    return true;
  default:
    return false;
  }
}

ParserRet parse_decimal(std::istream& i, stringstream& s){
  bool dot_start = false;
  int sharps_before_dot = 0;

  if(s.str().empty()){
    if(i.peek() == '.'){
      dot_start = true;
    }else{
      goto error;
    }
  }else{
    sharps_before_dot = eat_sharp(i, s);
  }

  if(i.peek() != '.'){
    goto end; // 1. no frac part
  }
  s.put(i.get());

  if(sharps_before_dot > 0){
    eat_sharp(i, s);
    goto end; // 4. only sharps after dot
  }

  if(dot_start && !is_number_char(10, i.peek()))
    goto error; // 2. dot start should have digits

  while(is_number_char(10, i.peek())){
    s.put(i.get());
  }

  eat_sharp(i, s);

 end:
  if(check_decimal_suffix(i.peek())){
    i.ignore(1);
    s.put('e');

    switch(i.peek()){
    case '+': case '-':
      s.put(i.get());
    }

    if(!is_number_char(10, i.peek())){
      goto error; // no number on exp. part
    }

    while(is_number_char(10, i.peek())){
      s.put(i.get());
    }
  }

  return {Number{strtod(s.str().c_str(), nullptr)},
      Exactness::inexact};

 error:
  return PARSE_ERROR_VALUE;
}

ParserRet parse_real_number(int radix, std::istream& i){
  int sign = 1;

  switch(i.peek()){
  case '+':
    sign = 1;
    i.ignore(1);
    break;
  case '-':
    sign = -1;
    i.ignore(1);
    break;
  default:
    sign = 1;
    break;
  }

  stringstream s;

  auto u1 = parse_unsigned(radix, i, s);
  if(!get<0>(u1)){
    if(i.peek() == '.'){
      goto decimal_float_check;
    }else{
      goto error;
    }
  }

  if(check_decimal_suffix(i.peek()) || i.peek() == '.'){
  decimal_float_check:
    if(radix == 10){
      auto n = parse_decimal(i, s);

      if(get<0>(n).type() == Number::Type::real){
        return {Number{get<0>(n).get<double>() * sign},
            Exactness::inexact};
      }
    }
    goto error;
  }

  if(i.peek() != '/'){ // integer?
    // FIXME: inexact or super-big integer can be fall into float.
    return {Number(sign * get<0>(u1).get<long>()), get<1>(u1)};
  }else{
    // rational
    stringstream s2;
    auto u2 = parse_unsigned(radix, i, s2);
    if(!get<0>(u2))
      goto error;
    return {Number(sign * get<0>(u1).get<double>() / get<0>(u2).get<double>()),
        Exactness::inexact};
  }

 error:
  return PARSE_ERROR_VALUE;
}

ParserRet parse_complex(int radix, std::istream& i){
  const auto first_char = i.peek();

  // has real part
  auto real = parse_real_number(radix, i);
  if(!get<0>(real))
    goto error;

  switch(auto c = i.peek()){
  case '@': {// polar literal
    i.ignore(1);
    auto deg = parse_real_number(radix, i);

    if(!get<0>(deg))
      goto error;

    return {Number{polar(get<0>(real).get<double>(), get<0>(deg).get<double>())},
        Exactness::inexact};
  }
  case '+': case '-': {
    i.ignore(1);
    const int sign = (c == '+') ? 1 : -1;

    if(i.peek() == 'i'){
      i.ignore(1);
      return {Number{get<0>(real).get<double>(), static_cast<double>(sign)},
          Exactness::inexact};
    }

    auto imag = parse_real_number(radix, i);
    if(!get<0>(imag) || i.get() != 'i')
      goto error;

    return {Number{get<0>(real).get<double>(), get<0>(imag).get<double>() * sign},
        Exactness::inexact};
  }
  case 'i':
    i.ignore(1);
    if(first_char == '+' || first_char == '-'){
      return {Number{0, get<0>(real).get<double>()},
          Exactness::inexact};
    }else{
      goto error;
    }
  default:
    return real;
  }

 error:
  return PARSE_ERROR_VALUE;
}

} // namespace

Number parse_number(std::istream& i){
  const auto prefix_info = parse_number_prefix(i);

  ParserRet r;

  switch(auto radix = get<0>(prefix_info)){
  case 2: case 8: case 10: case 16:
    r = parse_complex(radix, i);
    break;
  default:
    goto error;
  }

  if(!get<0>(r)) goto error;

  // TODO: check inexact integer, and warn.

  switch(auto e = get<1>(prefix_info)){
  case Exactness::exact:
    return (get<1>(r) == e) ? get<0>(r) : to_exact(get<0>(r));
  case Exactness::inexact:
    return (get<1>(r) == e) ? get<0>(r) : to_inexact(get<0>(r));
  case Exactness::unspecified:
    return get<0>(r);
  default:
    goto error;
  }

 error:
  return {};
}

bool eql(const Number& n, const Number& m){
  if(n.type() != m.type()) return false;

  switch(n.type()){
  case Number::Type::uninitialized:
    return false;
  case Number::Type::complex:
    return n.get<Number::complex_type>() == m.get<Number::complex_type>();
  case Number::Type::real:
    return n.get<Number::real_type>() == m.get<Number::real_type>();
  case Number::Type::integer:
    return n.get<Number::integer_type>() == m.get<Number::integer_type>();
  default:
    UNEXP_DEFAULT();
  }
}

void print(FILE* f, const Number& n){
  switch(n.type()){
  case Number::Type::uninitialized:
    fprintf(f, "(uninitialied number)");
    break;
  case Number::Type::complex: {
    auto&& z = n.get<Number::complex_type>();
    fprintf(f, "%g+%gi", z.real(), z.imag());
  }
    break;
  case Number::Type::real:
    fprintf(f, "%g", n.get<Number::real_type>());
    break;
  case Number::Type::integer:
    fprintf(f, "%ld", n.get<Number::integer_type>());
    break;
  default:
    UNEXP_DEFAULT();
  }
}

Number to_exact(const Number& n){
  switch(n.type()){
  case Number::Type::complex:
    return {}; // not supported
  case Number::Type::real:
    return {}; // not supported
  case Number::Type::integer:
    return n;
  case Number::Type::uninitialized:
  default:
    return {};
  }
}

Number to_inexact(const Number& n){
  switch(n.type()){
  case Number::Type::complex:
    return n;
  case Number::Type::real:
    return n;
  case Number::Type::integer:
    return Number{static_cast<Number::real_type>
        (n.get<Number::integer_type>())};
  case Number::Type::uninitialized:
  default:
    return {};
  }
}

const char* stringify(Number::Type t){
  switch(t){
  case Number::Type::uninitialized:
    return "uninitialized";
  case Number::Type::complex:
    return "complex";
  case Number::Type::real:
    return "real";
  case Number::Type::integer:
    return "integer";
  default:
    return "(unknown number type)";
  }
}

void describe(FILE* f, Number::Type t){
  fputs(stringify(t), f);
}

void describe(FILE* f, const Number& n){
  const auto t = n.type();

  fprintf(f, "Number: %s(", stringify(t));

  switch(t){
  case Number::Type::uninitialized:
    break;
  case Number::Type::complex: {
    const auto& z = n.get<Number::complex_type>();
    fprintf(f, "%g+%gi", z.real(), z.imag());
  }
    break;
  case Number::Type::real:
    fprintf(f, "%g", n.get<Number::real_type>());
    break;
  case Number::Type::integer:
    fprintf(f, "%ld", n.get<Number::integer_type>());
    break;
  default:
    break;
  }

  fputc(')', f);
}

<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/core/grappler/costs/analytical_cost_estimator.h"

#include <limits>
#include <unordered_map>

#include "tensorflow/core/framework/tensor_shape.pb.h"
#include "tensorflow/core/graph/types.h"
#include "tensorflow/core/grappler/costs/graph_properties.h"
#include "tensorflow/core/grappler/costs/op_performance_data.pb.h"
#include "tensorflow/core/grappler/costs/utils.h"
#include "tensorflow/core/grappler/costs/virtual_placer.h"
#include "tensorflow/core/grappler/costs/virtual_scheduler.h"
#include "tensorflow/core/grappler/grappler_item.h"

namespace tensorflow {
namespace grappler {

AnalyticalCostEstimator::AnalyticalCostEstimator(Cluster* cluster,
                                                 bool use_static_shapes)
    : cluster_(cluster),
      node_estimator_(new OpLevelCostEstimator()),
      node_manager_(VirtualScheduler::ReadyNodeManagerFactory("FirstReady")),
      use_static_shapes_(use_static_shapes) {}

AnalyticalCostEstimator::AnalyticalCostEstimator(
    Cluster* cluster, OpLevelCostEstimator* node_estimator,
    ReadyNodeManager* node_manager, bool use_static_shapes)
    : cluster_(cluster),
      node_estimator_(node_estimator),
      node_manager_(node_manager),
      use_static_shapes_(use_static_shapes) {}

Status AnalyticalCostEstimator::Initialize(const GrapplerItem& item) {
  item_ = item;
  return Status::OK();
}

Status AnalyticalCostEstimator::PredictCosts(const GraphDef& optimized_graph,
                                             CostGraphDef* cost_graph,
                                             Costs* costs) const {
  GrapplerItem item = item_;
  item.graph = optimized_graph;

  std::unordered_map<string, CostGraphDef::Node*> name_to_cost;
  if (cost_graph) {
    for (auto& node : *cost_graph->mutable_node()) {
      name_to_cost[node.name()] = &node;
    }
  }
  std::vector<string> inaccurate_nodes;
  VirtualScheduler scheduler(&item, use_static_shapes_, cluster_,
                             node_manager_.get());
  auto status = scheduler.Init();
  if (!status.ok()) {
    costs->execution_time = Costs::Duration::max();
    return status;
  }

  Costs node_costs;
  do {
    OpContext op_context = scheduler.GetCurrNode();
    const string& op_name = op_context.name;

    node_costs = node_estimator_->PredictCosts(op_context);
    if (node_costs.inaccurate) {
      inaccurate_nodes.push_back(op_name);
    }
    if (cost_graph) {
      auto it = name_to_cost.find(op_name);
      CostGraphDef::Node* cost_node;
      if (it != name_to_cost.end()) {
        cost_node = it->second;
      } else {
        cost_node = cost_graph->add_node();
        cost_node->set_name(op_name);
      }
      cost_node->set_device(op_context.device_name);
      cost_node->set_compute_cost(
          node_costs.execution_time.asMicroSeconds().count());
      cost_node->set_compute_time(
          node_costs.compute_time.asMicroSeconds().count());
      cost_node->set_memory_time(
          node_costs.memory_time.asMicroSeconds().count());
      for (const auto& output : op_context.op_info.outputs()) {
        auto output_info = cost_node->add_output_info();
        output_info->set_dtype(output.dtype());
        auto shape = output_info->mutable_shape();
        *shape = output.shape();
      }
    }
  } while (scheduler.MarkCurrNodeExecuted(node_costs));

  RunMetadata run_metadata;
  *costs = scheduler.Summary(&run_metadata);
  VLOG(1) << inaccurate_nodes.size() << " out of "
          << optimized_graph.node_size()
          << " nodes have inaccurate time estimation";
  if (VLOG_IS_ON(3)) {
    for (const auto& node : inaccurate_nodes) {
      VLOG(4) << "Node with inaccurate time estimation: " << node;
    }
  }

  if (VLOG_IS_ON(1)) {
    bool verbosity = VLOG_IS_ON(2);
    VLOG(1) << GetStatsStringFromRunMetadata(run_metadata, verbosity);
  }
  return Status::OK();
}

}  // end namespace grappler
}  // end namespace tensorflow
<commit_msg>Make logging more accurate<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/core/grappler/costs/analytical_cost_estimator.h"

#include <limits>
#include <unordered_map>

#include "tensorflow/core/framework/tensor_shape.pb.h"
#include "tensorflow/core/graph/types.h"
#include "tensorflow/core/grappler/costs/graph_properties.h"
#include "tensorflow/core/grappler/costs/op_performance_data.pb.h"
#include "tensorflow/core/grappler/costs/utils.h"
#include "tensorflow/core/grappler/costs/virtual_placer.h"
#include "tensorflow/core/grappler/costs/virtual_scheduler.h"
#include "tensorflow/core/grappler/grappler_item.h"

namespace tensorflow {
namespace grappler {

AnalyticalCostEstimator::AnalyticalCostEstimator(Cluster* cluster,
                                                 bool use_static_shapes)
    : cluster_(cluster),
      node_estimator_(new OpLevelCostEstimator()),
      node_manager_(VirtualScheduler::ReadyNodeManagerFactory("FirstReady")),
      use_static_shapes_(use_static_shapes) {}

AnalyticalCostEstimator::AnalyticalCostEstimator(
    Cluster* cluster, OpLevelCostEstimator* node_estimator,
    ReadyNodeManager* node_manager, bool use_static_shapes)
    : cluster_(cluster),
      node_estimator_(node_estimator),
      node_manager_(node_manager),
      use_static_shapes_(use_static_shapes) {}

Status AnalyticalCostEstimator::Initialize(const GrapplerItem& item) {
  item_ = item;
  return Status::OK();
}

Status AnalyticalCostEstimator::PredictCosts(const GraphDef& optimized_graph,
                                             CostGraphDef* cost_graph,
                                             Costs* costs) const {
  GrapplerItem item = item_;
  item.graph = optimized_graph;

  std::unordered_map<string, CostGraphDef::Node*> name_to_cost;
  if (cost_graph) {
    for (auto& node : *cost_graph->mutable_node()) {
      name_to_cost[node.name()] = &node;
    }
  }
  std::vector<string> inaccurate_nodes;
  int nodes_executed = 0;
  VirtualScheduler scheduler(&item, use_static_shapes_, cluster_,
                             node_manager_.get());
  auto status = scheduler.Init();
  if (!status.ok()) {
    costs->execution_time = Costs::Duration::max();
    return status;
  }

  Costs node_costs;
  do {
    ++nodes_executed;
    OpContext op_context = scheduler.GetCurrNode();
    const string& op_name = op_context.name;

    node_costs = node_estimator_->PredictCosts(op_context);
    if (node_costs.inaccurate) {
      inaccurate_nodes.push_back(op_name);
    }
    if (cost_graph) {
      auto it = name_to_cost.find(op_name);
      CostGraphDef::Node* cost_node;
      if (it != name_to_cost.end()) {
        cost_node = it->second;
      } else {
        cost_node = cost_graph->add_node();
        cost_node->set_name(op_name);
      }
      cost_node->set_device(op_context.device_name);
      cost_node->set_compute_cost(
          node_costs.execution_time.asMicroSeconds().count());
      cost_node->set_compute_time(
          node_costs.compute_time.asMicroSeconds().count());
      cost_node->set_memory_time(
          node_costs.memory_time.asMicroSeconds().count());
      for (const auto& output : op_context.op_info.outputs()) {
        auto output_info = cost_node->add_output_info();
        output_info->set_dtype(output.dtype());
        auto shape = output_info->mutable_shape();
        *shape = output.shape();
      }
    }
  } while (scheduler.MarkCurrNodeExecuted(node_costs));

  RunMetadata run_metadata;
  *costs = scheduler.Summary(&run_metadata);
  VLOG(1) << inaccurate_nodes.size() << " out of " << nodes_executed
          << " nodes have inaccurate time estimation";
  if (VLOG_IS_ON(3)) {
    for (const auto& node : inaccurate_nodes) {
      VLOG(4) << "Node with inaccurate time estimation: " << node;
    }
  }

  if (VLOG_IS_ON(1)) {
    bool verbosity = VLOG_IS_ON(2);
    VLOG(1) << GetStatsStringFromRunMetadata(run_metadata, verbosity);
  }
  return Status::OK();
}

}  // end namespace grappler
}  // end namespace tensorflow
<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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 <string>

#include "tensorflow/lite/tools/delegates/delegate_provider.h"
#include "tensorflow/lite/tools/evaluation/utils.h"
#if defined(__APPLE__)
#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
// Only enable metal delegate when using a real iPhone device.
#define REAL_IPHONE_DEVICE
#include "tensorflow/lite/experimental/delegates/coreml/coreml_delegate.h"
#endif
#endif

namespace tflite {
namespace tools {

class CoreMlDelegateProvider : public DelegateProvider {
 public:
  CoreMlDelegateProvider() {
#if defined(REAL_IPHONE_DEVICE)
    default_params_.AddParam("use_coreml", ToolParam::Create<bool>(false));
    default_params_.AddParam("coreml_version", ToolParam::Create<int>(0));
#endif
  }
  std::vector<Flag> CreateFlags(ToolParams* params) const final;

  void LogParams(const ToolParams& params) const final;

  TfLiteDelegatePtr CreateTfLiteDelegate(const ToolParams& params) const final;

  std::string GetName() const final { return "COREML"; }
};
REGISTER_DELEGATE_PROVIDER(CoreMlDelegateProvider);

std::vector<Flag> CoreMlDelegateProvider::CreateFlags(
    ToolParams* params) const {
#if defined(REAL_IPHONE_DEVICE)
  std::vector<Flag> flags = {
      CreateFlag<bool>("use_coreml", params, "use Core ML"),
      CreateFlag<int>("coreml_version", params,
                      "Target Core ML version for model conversion. "
                      "The default value is 0 and it means using the newest "
                      "version that's available on the device."),
  };
  return flags;
#else
  return {};
#endif
}

void CoreMlDelegateProvider::LogParams(const ToolParams& params) const {
#if defined(REAL_IPHONE_DEVICE)
  TFLITE_LOG(INFO) << "Use Core ML : [" << params.Get<bool>("use_coreml")
                   << "]";
#endif
}

TfLiteDelegatePtr CoreMlDelegateProvider::CreateTfLiteDelegate(
    const ToolParams& params) const {
  TfLiteDelegatePtr delegate(nullptr, [](TfLiteDelegate*) {});

#if defined(REAL_IPHONE_DEVICE)
  if (params.Get<bool>("use_coreml")) {
    TfLiteCoreMlDelegateOptions coreml_opts = {
        .enabled_devices = TfLiteCoreMlDelegateAllDevices};
    coreml_opts.coreml_version = params.Get<int>("coreml_version");
    coreml_opts.max_delegated_partitions =
        params.Get<int>("max_delegated_partitions");
    coreml_opts.min_nodes_per_partition =
        params.Get<int>("min_nodes_per_partition");
    delegate = TfLiteDelegatePtr(TfLiteCoreMlDelegateCreate(&coreml_opts),
                                 &TfLiteCoreMlDelegateDelete);
    if (!delegate) {
      TFLITE_LOG(WARN)
          << "CoreML acceleration is unsupported on this platform.";
    }
  }
#endif

  return delegate;
}

}  // namespace tools
}  // namespace tflite
<commit_msg>Config Core ML delegate provider correctly<commit_after>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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 <string>

#include "tensorflow/lite/tools/delegates/delegate_provider.h"
#include "tensorflow/lite/tools/evaluation/utils.h"
#if defined(__APPLE__)
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
// Only enable metal delegate when using a real iPhone device.
#define REAL_IPHONE_DEVICE
#include "tensorflow/lite/experimental/delegates/coreml/coreml_delegate.h"
#endif
#endif

namespace tflite {
namespace tools {

class CoreMlDelegateProvider : public DelegateProvider {
 public:
  CoreMlDelegateProvider() {
#if defined(REAL_IPHONE_DEVICE)
    default_params_.AddParam("use_coreml", ToolParam::Create<bool>(false));
    default_params_.AddParam("coreml_version", ToolParam::Create<int>(0));
#endif
  }
  std::vector<Flag> CreateFlags(ToolParams* params) const final;

  void LogParams(const ToolParams& params) const final;

  TfLiteDelegatePtr CreateTfLiteDelegate(const ToolParams& params) const final;

  std::string GetName() const final { return "COREML"; }
};
REGISTER_DELEGATE_PROVIDER(CoreMlDelegateProvider);

std::vector<Flag> CoreMlDelegateProvider::CreateFlags(
    ToolParams* params) const {
#if defined(REAL_IPHONE_DEVICE)
  std::vector<Flag> flags = {
      CreateFlag<bool>("use_coreml", params, "use Core ML"),
      CreateFlag<int>("coreml_version", params,
                      "Target Core ML version for model conversion. "
                      "The default value is 0 and it means using the newest "
                      "version that's available on the device."),
  };
  return flags;
#else
  return {};
#endif
}

void CoreMlDelegateProvider::LogParams(const ToolParams& params) const {
#if defined(REAL_IPHONE_DEVICE)
  TFLITE_LOG(INFO) << "Use Core ML : [" << params.Get<bool>("use_coreml")
                   << "]";
#endif
}

TfLiteDelegatePtr CoreMlDelegateProvider::CreateTfLiteDelegate(
    const ToolParams& params) const {
  TfLiteDelegatePtr delegate(nullptr, [](TfLiteDelegate*) {});

#if defined(REAL_IPHONE_DEVICE)
  if (params.Get<bool>("use_coreml")) {
    TfLiteCoreMlDelegateOptions coreml_opts = {
        .enabled_devices = TfLiteCoreMlDelegateAllDevices};
    coreml_opts.coreml_version = params.Get<int>("coreml_version");
    coreml_opts.max_delegated_partitions =
        params.Get<int>("max_delegated_partitions");
    coreml_opts.min_nodes_per_partition =
        params.Get<int>("min_nodes_per_partition");
    delegate = TfLiteDelegatePtr(TfLiteCoreMlDelegateCreate(&coreml_opts),
                                 &TfLiteCoreMlDelegateDelete);
    if (!delegate) {
      TFLITE_LOG(WARN)
          << "CoreML acceleration is unsupported on this platform.";
    }
  }
#endif

  return delegate;
}

}  // namespace tools
}  // namespace tflite
<|endoftext|>