<commit_before>//===========================================
//  Lumina Desktop Source Code
//  Copyright (c) 2016, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "page_mouse.h"
#include "ui_page_mouse.h"
#include "getPage.h"

#include <QSpinBox>
#include <QDoubleSpinBox>

//==========
//    PUBLIC
//==========
page_mouse::page_mouse(QWidget *parent) : PageWidget(parent), ui(new Ui::page_mouse()){
  ui->setupUi(this);
  devices = LInput::listDevices();
   //DEBUG Code
    /*qDebug() << "List Devices:";
    for(int i=0; i<devices.length(); i++){
      if(!devices[i]->isPointer()){
        ::free( devices.takeAt(i));
        i--;
      }else{
        qDebug() << "Found Pointer:" << devices[i]->devNumber();
        qDebug() << " - isExtension:" << devices[i]->isExtension();
        QList<int> props = devices[i]->listProperties();
        qDebug() << " - Properties:";
        for(int j=0; j<props.length(); j++){
          qDebug() << "   --" <<devices[i]->propertyName(props[j])+" ("+QString::number(props[j])+")" <<" = " << devices[i]->getPropertyValue(props[j]);
        }
      }
    }*/
  generateUI();
}

page_mouse::~page_mouse(){
  for(int i=0; i<devices.length(); i++){ ::free(devices[i]); }
}

//================
//    PUBLIC SLOTS
//================
void page_mouse::SaveSettings(){

  emit HasPendingChanges(false);
}

void page_mouse::LoadSettings(int){
  emit HasPendingChanges(false);
  emit ChangePageTitle( tr("Input Device Settings") );

}

void page_mouse::updateIcons(){
  for(int i=0; i<ui->tabWidget->count(); i++){
    ui->tabWidget->setTabIcon( i, LXDG::findIcon( "input-"+ui->tabWidget->tabWhatsThis(i).section(":",0,0), "" ) );
  }
}

//=================
//         PRIVATE
//=================
void page_mouse::generateUI(){
  ui->tabWidget->clear(); //remove all tabs (just in case)
  int mouse = 1;
  int keyboard = 1;
  qDebug() << "Devices Found:" << devices.length();
  for(int i=0; i<devices.length(); i++){
    QTreeWidget *tree = 0;
    if(!devices[i]->isExtension() || devices[i]->isPointer()){
      if(devices[i]->isPointer() && devices[i]->listProperties().count() <4){ continue; } //filter out all the trivial/static mouse devices
      //Make a new tab for this device
      tree = new QTreeWidget(this);
      tree->setHeaderHidden(true);
      tree->setColumnCount(2);
      connect(tree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(itemClicked(QTreeWidgetItem*,int)) );
      if(devices[i]->isPointer()){
        int tab = ui->tabWidget->addTab(tree, LXDG::findIcon("input-mouse",""), QString(tr("Mouse #%1")).arg(QString::number(mouse)) );
        ui->tabWidget->setTabWhatsThis(tab, "mouse:"+QString::number(devices[i]->devNumber()));
        mouse++;
      }else{
        int tab = ui->tabWidget->addTab(tree, LXDG::findIcon("input-keyboard",""), QString(tr("Keyboard #%1")).arg(QString::number(keyboard)) );
        ui->tabWidget->setTabWhatsThis(tab, "keyboard:"+QString::number(devices[i]->devNumber()) );
        keyboard++;
      }
    }else{
      //Find the associated tab for this extension device
      int tab = 0;
      QString type = devices[i]->isPointer() ? "mouse" : "keyboard";
      int num = devices[i]->devNumber();
      for(int t=ui->tabWidget->count()-1; t>0; t--){
        if(ui->tabWidget->tabWhatsThis(t).startsWith(type) && ui->tabWidget->tabWhatsThis(t).section(":",-1).toInt() < num ){ tab = t; break; }
      }
      tree = static_cast<QTreeWidget*>( ui->tabWidget->widget(tab) );
    }
    if(tree!=0){ populateDeviceTree(tree, devices[i]); }
  }
}

void page_mouse::populateDeviceTree(QTreeWidget *tree, LInputDevice *device){
 QTreeWidgetItem *top = new QTreeWidgetItem(tree);
  if(device->isExtension()){
    top->setText( 0, QString(tr("Extension Device #%1")).arg(QString::number(tree->topLevelItemCount())) );
  }else{  top->setText(0, tr("Master Device")); }
  top->setWhatsThis(0, QString(device->isPointer() ? "mouse" : "keyboard")+":"+QString::number(device->devNumber()) ); //save this for later
  top->setFirstColumnSpanned(true);
  top->setExpanded(true);
  tree->addTopLevelItem(top);
  //Now add all the child properties to this item
  QList<int> props = device->listProperties();
  for(int i=0; i<props.length(); i++){
    if(device->propertyName(props[i]).toLower().contains("matrix")){ continue; } //skip this one - can not change from UI and most people will never want to anyway
    QTreeWidgetItem *tmp = new QTreeWidgetItem(top);
      tmp->setWhatsThis(0, QString::number(props[i]) );
      tmp->setText(0, device->propertyName(props[i]));
      top->addChild(tmp);
      populateDeviceItemValue(tree, tmp, device->getPropertyValue(props[i]), QString::number(device->devNumber())+":"+QString::number(props[i]) );
  }
  //Clean up the tree widget as needed
  top->sortChildren(0, Qt::AscendingOrder);
  tree->resizeColumnToContents(0);
}

void page_mouse::populateDeviceItemValue(QTreeWidget *tree, QTreeWidgetItem *it, QVariant value, QString id){
  if(value.type()==QVariant::Int){
    //Could be a boolian - check the name for known "enable" states
    if(value.toInt() < 2 && (it->text(0).toLower().contains("enable") || it->text(0).toLower().contains("emulation") || it->text(0)==("XTEST Device") ) ){
      //Just use a checkable column within the item
      bool enabled = (value.toInt()==1);
      it->setText(1,"");
      it->setWhatsThis(1, "bool:"+id);
      it->setCheckState(1, enabled ? Qt::Checked : Qt::Unchecked);
    }else{
      //Use a QSpinBox
      QSpinBox *box = new QSpinBox();
        box->setRange(0,100);
        box->setValue( value.toInt() );
	box->setWhatsThis("int:"+id);
      tree->setItemWidget(it, 1, box);
      connect(box, SIGNAL(valueChanged(int)), this, SLOT(valueChanged()) );
    }
  }else if(value.type()==QVariant::Double){
  //Use a QDoubleSpinBox
  QDoubleSpinBox *box = new QDoubleSpinBox();
      box->setRange(0,1000);
      box->setValue( value.toInt() );
      box->setWhatsThis("double:"+id);
    tree->setItemWidget(it, 1, box);
    connect(box, SIGNAL(valueChanged(double)), this, SLOT(valueChanged()) );

  }else if(value.canConvert< QList<QVariant> >()){
    //Not Modifiable - just use the label in the item
    QList<QVariant> list = value.toList();
    QStringList txtList;
    for(int i=0; i<list.length(); i++){ txtList << list[i].toString(); }
    it->setText(1, txtList.join(", ") );
    it->setToolTip(1, txtList.join(", "));
  }else if( value.canConvert<QString>() ){
    //Not Modifiable - just use the label in the item
    it->setText(1, value.toString());
  }
}
//=================
//    PRIVATE SLOTS
//=================
void page_mouse::valueChanged(){
  //Now get the currently focused widget
   QWidget *foc = this->focusWidget();
   if(foc==0){ return; }
  //qDebug() << "Focus Widget:" << foc->whatsThis();
  //Now pull out the value and device/property numbers
  unsigned int dev = foc->whatsThis().section(":",1,1).toInt();
  int prop = foc->whatsThis().section(":",2,2).toInt();
  QVariant value;
  if(foc->whatsThis().startsWith("int:")){ value.setValue( static_cast<QSpinBox*>(foc)->value() ); }
  else if(foc->whatsThis().startsWith("double:")){ value.setValue( static_cast<QDoubleSpinBox*>(foc)->value() ); }
  //Now change the property for the device
  qDebug() << " - Device:" <<dev << "prop:" << prop << "value:" << value;
  for(int i=0; i<devices.length(); i++){
    if(devices[i]->devNumber() == dev){
      bool ok = devices[i]->setPropertyValue(prop, value);
      if(ok){ foc->setStyleSheet(""); }
      else{ foc->setStyleSheet("background: red"); }
      //qDebug() << " - Changed property:" << (ok ? "success" : "failure");
      break;
    }
  }
}

void page_mouse::itemClicked(QTreeWidgetItem *it, int col){
  if(col!=1){ return; } //only care about value changes
  if(it->whatsThis(1).isEmpty()){ return; }//not a checkable item
  qDebug() << "item Clicked:" << it->whatsThis(1) << it->text(0);
  //Now pull out the value and device/property numbers
  unsigned int dev = it->whatsThis(1).section(":",1,1).toInt();
  int prop = it->whatsThis(1).section(":",2,2).toInt();
  QVariant value( (it->checkState(1)==Qt::Checked) ? 1 : 0 );
 //Now change the property for the device
  qDebug() << " - Device:" <<dev << "prop:" << prop << "value:" << value;
  for(int i=0; i<devices.length(); i++){
    if(devices[i]->devNumber() == dev){
      //Since this "clicked" signal can get sent out even if the value has not changed, go ahead and make sure we have a different value first
      QVariant current = devices[i]->getPropertyValue(prop);
      //qDebug() << " - Current Value:" << current;
      if(value.toInt()!=current.toInt()){
        bool ok = devices[i]->setPropertyValue(prop, value);
        //if(ok){ foc->setStyleSheet(""); }
        //else{ foc->setStyleSheet("background: red"); }
        qDebug() << " - Changed property:" << (ok ? "success" : "failure");
      }
      break;
    }
  }
}
<commit_msg>Switch the "clicked" signal for the "Activated" signal within the input device checkbox detection. This will allow keyboard changes to be detected/applied as well.<commit_after>//===========================================
//  Lumina Desktop Source Code
//  Copyright (c) 2016, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "page_mouse.h"
#include "ui_page_mouse.h"
#include "getPage.h"

#include <QSpinBox>
#include <QDoubleSpinBox>

//==========
//    PUBLIC
//==========
page_mouse::page_mouse(QWidget *parent) : PageWidget(parent), ui(new Ui::page_mouse()){
  ui->setupUi(this);
  devices = LInput::listDevices();
   //DEBUG Code
    /*qDebug() << "List Devices:";
    for(int i=0; i<devices.length(); i++){
      if(!devices[i]->isPointer()){
        ::free( devices.takeAt(i));
        i--;
      }else{
        qDebug() << "Found Pointer:" << devices[i]->devNumber();
        qDebug() << " - isExtension:" << devices[i]->isExtension();
        QList<int> props = devices[i]->listProperties();
        qDebug() << " - Properties:";
        for(int j=0; j<props.length(); j++){
          qDebug() << "   --" <<devices[i]->propertyName(props[j])+" ("+QString::number(props[j])+")" <<" = " << devices[i]->getPropertyValue(props[j]);
        }
      }
    }*/
  generateUI();
}

page_mouse::~page_mouse(){
  for(int i=0; i<devices.length(); i++){ ::free(devices[i]); }
}

//================
//    PUBLIC SLOTS
//================
void page_mouse::SaveSettings(){

  emit HasPendingChanges(false);
}

void page_mouse::LoadSettings(int){
  emit HasPendingChanges(false);
  emit ChangePageTitle( tr("Input Device Settings") );

}

void page_mouse::updateIcons(){
  for(int i=0; i<ui->tabWidget->count(); i++){
    ui->tabWidget->setTabIcon( i, LXDG::findIcon( "input-"+ui->tabWidget->tabWhatsThis(i).section(":",0,0), "" ) );
  }
}

//=================
//         PRIVATE
//=================
void page_mouse::generateUI(){
  ui->tabWidget->clear(); //remove all tabs (just in case)
  int mouse = 1;
  int keyboard = 1;
  qDebug() << "Devices Found:" << devices.length();
  for(int i=0; i<devices.length(); i++){
    QTreeWidget *tree = 0;
    if(!devices[i]->isExtension() || devices[i]->isPointer()){
      if(devices[i]->isPointer() && devices[i]->listProperties().count() <4){ continue; } //filter out all the trivial/static mouse devices
      //Make a new tab for this device
      tree = new QTreeWidget(this);
      tree->setHeaderHidden(true);
      tree->setColumnCount(2);
      connect(tree, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(itemClicked(QTreeWidgetItem*,int)) );
      if(devices[i]->isPointer()){
        int tab = ui->tabWidget->addTab(tree, LXDG::findIcon("input-mouse",""), QString(tr("Mouse #%1")).arg(QString::number(mouse)) );
        ui->tabWidget->setTabWhatsThis(tab, "mouse:"+QString::number(devices[i]->devNumber()));
        mouse++;
      }else{
        int tab = ui->tabWidget->addTab(tree, LXDG::findIcon("input-keyboard",""), QString(tr("Keyboard #%1")).arg(QString::number(keyboard)) );
        ui->tabWidget->setTabWhatsThis(tab, "keyboard:"+QString::number(devices[i]->devNumber()) );
        keyboard++;
      }
    }else{
      //Find the associated tab for this extension device
      int tab = 0;
      QString type = devices[i]->isPointer() ? "mouse" : "keyboard";
      int num = devices[i]->devNumber();
      for(int t=ui->tabWidget->count()-1; t>0; t--){
        if(ui->tabWidget->tabWhatsThis(t).startsWith(type) && ui->tabWidget->tabWhatsThis(t).section(":",-1).toInt() < num ){ tab = t; break; }
      }
      tree = static_cast<QTreeWidget*>( ui->tabWidget->widget(tab) );
    }
    if(tree!=0){ populateDeviceTree(tree, devices[i]); }
  }
}

void page_mouse::populateDeviceTree(QTreeWidget *tree, LInputDevice *device){
 QTreeWidgetItem *top = new QTreeWidgetItem(tree);
  if(device->isExtension()){
    top->setText( 0, QString(tr("Extension Device #%1")).arg(QString::number(tree->topLevelItemCount())) );
  }else{  top->setText(0, tr("Master Device")); }
  top->setWhatsThis(0, QString(device->isPointer() ? "mouse" : "keyboard")+":"+QString::number(device->devNumber()) ); //save this for later
  top->setFirstColumnSpanned(true);
  top->setExpanded(true);
  tree->addTopLevelItem(top);
  //Now add all the child properties to this item
  QList<int> props = device->listProperties();
  for(int i=0; i<props.length(); i++){
    if(device->propertyName(props[i]).toLower().contains("matrix")){ continue; } //skip this one - can not change from UI and most people will never want to anyway
    QTreeWidgetItem *tmp = new QTreeWidgetItem(top);
      tmp->setWhatsThis(0, QString::number(props[i]) );
      tmp->setText(0, device->propertyName(props[i]));
      top->addChild(tmp);
      populateDeviceItemValue(tree, tmp, device->getPropertyValue(props[i]), QString::number(device->devNumber())+":"+QString::number(props[i]) );
  }
  //Clean up the tree widget as needed
  top->sortChildren(0, Qt::AscendingOrder);
  tree->resizeColumnToContents(0);
}

void page_mouse::populateDeviceItemValue(QTreeWidget *tree, QTreeWidgetItem *it, QVariant value, QString id){
  if(value.type()==QVariant::Int){
    //Could be a boolian - check the name for known "enable" states
    if(value.toInt() < 2 && (it->text(0).toLower().contains("enable") || it->text(0).toLower().contains("emulation") || it->text(0)==("XTEST Device") ) ){
      //Just use a checkable column within the item
      bool enabled = (value.toInt()==1);
      it->setText(1,"");
      it->setWhatsThis(1, "bool:"+id);
      it->setCheckState(1, enabled ? Qt::Checked : Qt::Unchecked);
    }else{
      //Use a QSpinBox
      QSpinBox *box = new QSpinBox();
        box->setRange(0,100);
        box->setValue( value.toInt() );
	box->setWhatsThis("int:"+id);
      tree->setItemWidget(it, 1, box);
      connect(box, SIGNAL(valueChanged(int)), this, SLOT(valueChanged()) );
    }
  }else if(value.type()==QVariant::Double){
  //Use a QDoubleSpinBox
  QDoubleSpinBox *box = new QDoubleSpinBox();
      box->setRange(0,1000);
      box->setValue( value.toInt() );
      box->setWhatsThis("double:"+id);
    tree->setItemWidget(it, 1, box);
    connect(box, SIGNAL(valueChanged(double)), this, SLOT(valueChanged()) );

  }else if(value.canConvert< QList<QVariant> >()){
    //Not Modifiable - just use the label in the item
    QList<QVariant> list = value.toList();
    QStringList txtList;
    for(int i=0; i<list.length(); i++){ txtList << list[i].toString(); }
    it->setText(1, txtList.join(", ") );
    it->setToolTip(1, txtList.join(", "));
  }else if( value.canConvert<QString>() ){
    //Not Modifiable - just use the label in the item
    it->setText(1, value.toString());
  }
}
//=================
//    PRIVATE SLOTS
//=================
void page_mouse::valueChanged(){
  //Now get the currently focused widget
   QWidget *foc = this->focusWidget();
   if(foc==0){ return; }
  //qDebug() << "Focus Widget:" << foc->whatsThis();
  //Now pull out the value and device/property numbers
  unsigned int dev = foc->whatsThis().section(":",1,1).toInt();
  int prop = foc->whatsThis().section(":",2,2).toInt();
  QVariant value;
  if(foc->whatsThis().startsWith("int:")){ value.setValue( static_cast<QSpinBox*>(foc)->value() ); }
  else if(foc->whatsThis().startsWith("double:")){ value.setValue( static_cast<QDoubleSpinBox*>(foc)->value() ); }
  //Now change the property for the device
  qDebug() << " - Device:" <<dev << "prop:" << prop << "value:" << value;
  for(int i=0; i<devices.length(); i++){
    if(devices[i]->devNumber() == dev){
      bool ok = devices[i]->setPropertyValue(prop, value);
      if(ok){ foc->setStyleSheet(""); }
      else{ foc->setStyleSheet("background: red"); }
      //qDebug() << " - Changed property:" << (ok ? "success" : "failure");
      break;
    }
  }
}

void page_mouse::itemClicked(QTreeWidgetItem *it, int col){
  if(col!=1){ return; } //only care about value changes
  if(it->whatsThis(1).isEmpty()){ return; }//not a checkable item
  qDebug() << "item Clicked:" << it->whatsThis(1) << it->text(0);
  //Now pull out the value and device/property numbers
  unsigned int dev = it->whatsThis(1).section(":",1,1).toInt();
  int prop = it->whatsThis(1).section(":",2,2).toInt();
  QVariant value( (it->checkState(1)==Qt::Checked) ? 1 : 0 );
 //Now change the property for the device
  qDebug() << " - Device:" <<dev << "prop:" << prop << "value:" << value;
  for(int i=0; i<devices.length(); i++){
    if(devices[i]->devNumber() == dev){
      //Since this "clicked" signal can get sent out even if the value has not changed, go ahead and make sure we have a different value first
      QVariant current = devices[i]->getPropertyValue(prop);
      //qDebug() << " - Current Value:" << current;
      if(value.toInt()!=current.toInt()){
        bool ok = devices[i]->setPropertyValue(prop, value);
        //if(ok){ foc->setStyleSheet(""); }
        //else{ foc->setStyleSheet("background: red"); }
        qDebug() << " - Changed property:" << (ok ? "success" : "failure");
      }
      break;
    }
  }
}
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014-2017 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "colorentity.h"

// appleseed.renderer headers.
#include "renderer/global/globallogger.h"
#include "renderer/modeling/color/wavelengths.h"
#include "renderer/utility/paramarray.h"

// appleseed.foundation headers.
#include "foundation/utility/api/specializedapiarrays.h"
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/iostreamop.h"

// Standard headers.
#include <cassert>
#include <string>

using namespace foundation;
using namespace std;

namespace renderer
{

//
// ColorEntity class implementation.
//

namespace
{
    const UniqueID g_class_uid = new_guid();
}

UniqueID ColorEntity::get_class_uid()
{
    return g_class_uid;
}

struct ColorEntity::Impl
{
    ColorValueArray         m_values;
    ColorValueArray         m_alpha;
    ColorSpace              m_color_space;
    Vector2f                m_wavelength_range;
    float                   m_multiplier;
};

ColorEntity::ColorEntity(
    const char*             name,
    const ParamArray&       params)
  : Entity(g_class_uid, params)
  , impl(new Impl())
{
    set_name(name);

    extract_parameters();
    extract_values();

    check_validity();
}

ColorEntity::ColorEntity(
    const char*             name,
    const ParamArray&       params,
    const ColorValueArray&  values)
  : Entity(g_class_uid, params)
  , impl(new Impl())
{
    set_name(name);

    extract_parameters();

    impl->m_values = values;
    impl->m_alpha.push_back(1.0f);

    check_validity();
}

ColorEntity::ColorEntity(
    const char*             name,
    const ParamArray&       params,
    const ColorValueArray&  values,
    const ColorValueArray&  alpha)
  : Entity(g_class_uid, params)
  , impl(new Impl())
{
    set_name(name);

    extract_parameters();

    impl->m_values = values;
    impl->m_alpha = alpha;

    check_validity();
}

ColorEntity::~ColorEntity()
{
    delete impl;
}

void ColorEntity::extract_parameters()
{
    // Retrieve the color space.
    const ColorSpace DefaultColorSpace = ColorSpaceSRGB;
    const char* DefaultColorSpaceName = color_space_name(DefaultColorSpace);
    const string color_space = m_params.get_required<string>("color_space", DefaultColorSpaceName);
    if (color_space == "linear_rgb")
        impl->m_color_space = ColorSpaceLinearRGB;
    else if (color_space == "srgb")
        impl->m_color_space = ColorSpaceSRGB;
    else if (color_space == "ciexyz")
        impl->m_color_space = ColorSpaceCIEXYZ;
    else if (color_space == "spectral")
        impl->m_color_space = ColorSpaceSpectral;
    else
    {
        RENDERER_LOG_ERROR(
            "invalid value \"%s\" for parameter \"color_space\", "
            "using default value \"%s\".",
            color_space.c_str(),
            DefaultColorSpaceName);
        impl->m_color_space = DefaultColorSpace;
    }

    // For the spectral color space, retrieve the wavelength range.
    if (impl->m_color_space == ColorSpaceSpectral)
    {
        const Vector2f DefaultWavelengthRange(LowWavelength, HighWavelength);
        impl->m_wavelength_range =
            m_params.get_required<Vector2f>(
                "wavelength_range",
                DefaultWavelengthRange);

        if (impl->m_wavelength_range[0] < 0.0 ||
            impl->m_wavelength_range[1] < 0.0 ||
            impl->m_wavelength_range[0] >= impl->m_wavelength_range[1])
        {
            RENDERER_LOG_ERROR(
                "invalid value \"%f %f\" for parameter \"%s\", "
                "using default value \"%f %f\".",
                impl->m_wavelength_range[0],
                impl->m_wavelength_range[1],
                "wavelength_range",
                DefaultWavelengthRange[0],
                DefaultWavelengthRange[1]);

            impl->m_wavelength_range = DefaultWavelengthRange;
        }
    }
    else
    {
        impl->m_wavelength_range[0] =
        impl->m_wavelength_range[1] = 0.0f;
    }

    // Retrieve multiplier.
    impl->m_multiplier = m_params.get_optional<float>("multiplier", 1.0f);
}

void ColorEntity::extract_values()
{
    ColorValueArray black;
    black.push_back(0.0f);

    ColorValueArray opaque;
    opaque.push_back(1.0f);

    impl->m_values = m_params.get_required("color", black);
    impl->m_alpha = m_params.get_optional("alpha", opaque);

    m_params.strings().remove("color");
    m_params.strings().remove("alpha");
}

void ColorEntity::check_validity()
{
    // Check the number of color values.
    if (impl->m_color_space == ColorSpaceSpectral)
    {
        if (impl->m_values.empty())
        {
            RENDERER_LOG_ERROR("1 or more values required for \"spectral\" color space, got 0.");
        }
    }
    else
    {
        if (impl->m_values.size() != 1 && impl->m_values.size() != 3)
        {
            RENDERER_LOG_ERROR(
                "1 or 3 values required for \"%s\" color space, got " FMT_SIZE_T ".",
                color_space_name(impl->m_color_space),
                impl->m_values.size());
        }
    }
}

void ColorEntity::release()
{
    delete this;
}

const ColorValueArray& ColorEntity::get_values() const
{
    return impl->m_values;
}

const ColorValueArray& ColorEntity::get_alpha() const
{
    return impl->m_alpha;
}

ColorSpace ColorEntity::get_color_space() const
{
    return impl->m_color_space;
}

const Vector2f& ColorEntity::get_wavelength_range() const
{
    assert(impl->m_color_space == ColorSpaceSpectral);
    return impl->m_wavelength_range;
}

float ColorEntity::get_multiplier() const
{
    return impl->m_multiplier;
}

//
// ColorEntityFactory class implementation.
//

DictionaryArray ColorEntityFactory::get_input_metadata()
{
    DictionaryArray metadata;

    metadata.push_back(
        Dictionary()
            .insert("name", "color_space")
            .insert("label", "Color Space")
            .insert("type", "enumeration")
            .insert("items",
                Dictionary()
                    .insert("Linear RGB", "linear_rgb")
                    .insert("sRGB", "srgb")
                    .insert("CIE XYZ", "ciexyz")
                    .insert("Spectral", "spectral"))
            .insert("default", "srgb")
            .insert("use", "required")
            .insert("on_change", "rebuild_form"));

    metadata.push_back(
        Dictionary()
            .insert("name", "wavelength_range")
            .insert("label", "Wavelength Range")
            .insert("type", "text")
            .insert("default", "400.0 700.0")
            .insert("use", "optional")
            .insert("on_change", "rebuild_form"));

    metadata.push_back(
        Dictionary()
            .insert("name", "color")
            .insert("label", "Color")
            .insert("type", "color")
            .insert("wavelength_range_widget", "wavelength_range")
            .insert("default", "0.0 0.0 0.0")
            .insert("use", "required"));

    metadata.push_back(
        Dictionary()
            .insert("name", "alpha")
            .insert("label", "Alpha")
            .insert("type", "numeric")
            .insert("min_value", "0.0")
            .insert("max_value", "1.0")
            .insert("default", "1.0")
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "multiplier")
            .insert("label", "Multiplier")
            .insert("type", "numeric")
            .insert("min_value", "0.0")
            .insert("max_value", "10.0")
            .insert("default", "1.0")
            .insert("use", "optional"));

    return metadata;
}

auto_release_ptr<ColorEntity> ColorEntityFactory::create(
    const char*             name,
    const ParamArray&       params)
{
    return
        auto_release_ptr<ColorEntity>(
            new ColorEntity(name, params));
}

auto_release_ptr<ColorEntity> ColorEntityFactory::create(
    const char*             name,
    const ParamArray&       params,
    const ColorValueArray&  values)
{
    return
        auto_release_ptr<ColorEntity>(
            new ColorEntity(name, params, values));
}

auto_release_ptr<ColorEntity> ColorEntityFactory::create(
    const char*             name,
    const ParamArray&       params,
    const ColorValueArray&  values,
    const ColorValueArray&  alpha)
{
    return
        auto_release_ptr<ColorEntity>(
            new ColorEntity(name, params, values, alpha));
}

}   // namespace renderer
<commit_msg>Hide wavelength range when editing non-spectral colors<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014-2017 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "colorentity.h"

// appleseed.renderer headers.
#include "renderer/global/globallogger.h"
#include "renderer/modeling/color/wavelengths.h"
#include "renderer/utility/paramarray.h"

// appleseed.foundation headers.
#include "foundation/utility/api/specializedapiarrays.h"
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/iostreamop.h"

// Standard headers.
#include <cassert>
#include <string>

using namespace foundation;
using namespace std;

namespace renderer
{

//
// ColorEntity class implementation.
//

namespace
{
    const UniqueID g_class_uid = new_guid();
}

UniqueID ColorEntity::get_class_uid()
{
    return g_class_uid;
}

struct ColorEntity::Impl
{
    ColorValueArray         m_values;
    ColorValueArray         m_alpha;
    ColorSpace              m_color_space;
    Vector2f                m_wavelength_range;
    float                   m_multiplier;
};

ColorEntity::ColorEntity(
    const char*             name,
    const ParamArray&       params)
  : Entity(g_class_uid, params)
  , impl(new Impl())
{
    set_name(name);

    extract_parameters();
    extract_values();

    check_validity();
}

ColorEntity::ColorEntity(
    const char*             name,
    const ParamArray&       params,
    const ColorValueArray&  values)
  : Entity(g_class_uid, params)
  , impl(new Impl())
{
    set_name(name);

    extract_parameters();

    impl->m_values = values;
    impl->m_alpha.push_back(1.0f);

    check_validity();
}

ColorEntity::ColorEntity(
    const char*             name,
    const ParamArray&       params,
    const ColorValueArray&  values,
    const ColorValueArray&  alpha)
  : Entity(g_class_uid, params)
  , impl(new Impl())
{
    set_name(name);

    extract_parameters();

    impl->m_values = values;
    impl->m_alpha = alpha;

    check_validity();
}

ColorEntity::~ColorEntity()
{
    delete impl;
}

void ColorEntity::extract_parameters()
{
    // Retrieve the color space.
    const ColorSpace DefaultColorSpace = ColorSpaceSRGB;
    const char* DefaultColorSpaceName = color_space_name(DefaultColorSpace);
    const string color_space = m_params.get_required<string>("color_space", DefaultColorSpaceName);
    if (color_space == "linear_rgb")
        impl->m_color_space = ColorSpaceLinearRGB;
    else if (color_space == "srgb")
        impl->m_color_space = ColorSpaceSRGB;
    else if (color_space == "ciexyz")
        impl->m_color_space = ColorSpaceCIEXYZ;
    else if (color_space == "spectral")
        impl->m_color_space = ColorSpaceSpectral;
    else
    {
        RENDERER_LOG_ERROR(
            "invalid value \"%s\" for parameter \"color_space\", "
            "using default value \"%s\".",
            color_space.c_str(),
            DefaultColorSpaceName);
        impl->m_color_space = DefaultColorSpace;
    }

    // For the spectral color space, retrieve the wavelength range.
    if (impl->m_color_space == ColorSpaceSpectral)
    {
        const Vector2f DefaultWavelengthRange(LowWavelength, HighWavelength);
        impl->m_wavelength_range =
            m_params.get_required<Vector2f>(
                "wavelength_range",
                DefaultWavelengthRange);

        if (impl->m_wavelength_range[0] < 0.0 ||
            impl->m_wavelength_range[1] < 0.0 ||
            impl->m_wavelength_range[0] >= impl->m_wavelength_range[1])
        {
            RENDERER_LOG_ERROR(
                "invalid value \"%f %f\" for parameter \"%s\", "
                "using default value \"%f %f\".",
                impl->m_wavelength_range[0],
                impl->m_wavelength_range[1],
                "wavelength_range",
                DefaultWavelengthRange[0],
                DefaultWavelengthRange[1]);

            impl->m_wavelength_range = DefaultWavelengthRange;
        }
    }
    else
    {
        impl->m_wavelength_range[0] =
        impl->m_wavelength_range[1] = 0.0f;
    }

    // Retrieve multiplier.
    impl->m_multiplier = m_params.get_optional<float>("multiplier", 1.0f);
}

void ColorEntity::extract_values()
{
    ColorValueArray black;
    black.push_back(0.0f);

    ColorValueArray opaque;
    opaque.push_back(1.0f);

    impl->m_values = m_params.get_required("color", black);
    impl->m_alpha = m_params.get_optional("alpha", opaque);

    m_params.strings().remove("color");
    m_params.strings().remove("alpha");
}

void ColorEntity::check_validity()
{
    // Check the number of color values.
    if (impl->m_color_space == ColorSpaceSpectral)
    {
        if (impl->m_values.empty())
        {
            RENDERER_LOG_ERROR("1 or more values required for \"spectral\" color space, got 0.");
        }
    }
    else
    {
        if (impl->m_values.size() != 1 && impl->m_values.size() != 3)
        {
            RENDERER_LOG_ERROR(
                "1 or 3 values required for \"%s\" color space, got " FMT_SIZE_T ".",
                color_space_name(impl->m_color_space),
                impl->m_values.size());
        }
    }
}

void ColorEntity::release()
{
    delete this;
}

const ColorValueArray& ColorEntity::get_values() const
{
    return impl->m_values;
}

const ColorValueArray& ColorEntity::get_alpha() const
{
    return impl->m_alpha;
}

ColorSpace ColorEntity::get_color_space() const
{
    return impl->m_color_space;
}

const Vector2f& ColorEntity::get_wavelength_range() const
{
    assert(impl->m_color_space == ColorSpaceSpectral);
    return impl->m_wavelength_range;
}

float ColorEntity::get_multiplier() const
{
    return impl->m_multiplier;
}

//
// ColorEntityFactory class implementation.
//

DictionaryArray ColorEntityFactory::get_input_metadata()
{
    DictionaryArray metadata;

    metadata.push_back(
        Dictionary()
            .insert("name", "color_space")
            .insert("label", "Color Space")
            .insert("type", "enumeration")
            .insert("items",
                Dictionary()
                    .insert("Linear RGB", "linear_rgb")
                    .insert("sRGB", "srgb")
                    .insert("CIE XYZ", "ciexyz")
                    .insert("Spectral", "spectral"))
            .insert("default", "srgb")
            .insert("use", "required")
            .insert("on_change", "rebuild_form"));

    metadata.push_back(
        Dictionary()
            .insert("name", "wavelength_range")
            .insert("label", "Wavelength Range")
            .insert("type", "text")
            .insert("default", "400.0 700.0")
            .insert("use", "optional")
            .insert("visible_if",
                Dictionary()
                    .insert("color_space", "spectral")));

    metadata.push_back(
        Dictionary()
            .insert("name", "color")
            .insert("label", "Color")
            .insert("type", "color")
            .insert("wavelength_range_widget", "wavelength_range")
            .insert("default", "0.0 0.0 0.0")
            .insert("use", "required"));

    metadata.push_back(
        Dictionary()
            .insert("name", "alpha")
            .insert("label", "Alpha")
            .insert("type", "numeric")
            .insert("min_value", "0.0")
            .insert("max_value", "1.0")
            .insert("default", "1.0")
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "multiplier")
            .insert("label", "Multiplier")
            .insert("type", "numeric")
            .insert("min_value", "0.0")
            .insert("max_value", "10.0")
            .insert("default", "1.0")
            .insert("use", "optional"));

    return metadata;
}

auto_release_ptr<ColorEntity> ColorEntityFactory::create(
    const char*             name,
    const ParamArray&       params)
{
    return
        auto_release_ptr<ColorEntity>(
            new ColorEntity(name, params));
}

auto_release_ptr<ColorEntity> ColorEntityFactory::create(
    const char*             name,
    const ParamArray&       params,
    const ColorValueArray&  values)
{
    return
        auto_release_ptr<ColorEntity>(
            new ColorEntity(name, params, values));
}

auto_release_ptr<ColorEntity> ColorEntityFactory::create(
    const char*             name,
    const ParamArray&       params,
    const ColorValueArray&  values,
    const ColorValueArray&  alpha)
{
    return
        auto_release_ptr<ColorEntity>(
            new ColorEntity(name, params, values, alpha));
}

}   // namespace renderer
<|endoftext|>


<commit_before>// This plugin looks at its own filename and uses that to find a config file that tells it how to work.
// The config file looks like this:
//
// [Settings]
// Name=Some name (for display purposes)
// Command=program.exe "%input%" "%output%"
//
// You can put anything in the Command, %input% and %output% will be substituted with filenames
// (possibly with spaces). Non-zero return codes will be interpreted as an error.
// TODO: allow stdin/stdout?

#pragma warning(push,3)
#include <windows.h>
#include <cstdint>
#include <string>
#include <sstream>
#pragma warning(pop)

using namespace ::std;

HINSTANCE g_hInstance;

extern "C" BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD, LPVOID)
{
	g_hInstance = hInst;
	return TRUE;
}

string getConfigFilename()
{
	static string filename;
	if (!filename.empty())
	{
		return filename;
	}

	char* buffer = NULL;
	unsigned int bufferSize = 256;
	bool success = false;
	while (!success && bufferSize < 1024*1024*1024)
	{
		delete [] buffer;
		buffer = new char[bufferSize];

		// Try to get the DLL filename.
		// This returns the number of chars copied on success, 0 otherwise.
		DWORD result = GetModuleFileName(g_hInstance, buffer, bufferSize);
		success = result != bufferSize;
		bufferSize *= 2;
	}
	filename = std::string(buffer);
	delete [] buffer;
	// We append .ini
	filename += ".ini";
	return filename;
}

string getSetting(const string& name)
{
	const std::string& configFilename = getConfigFilename();
	std::string setting;

	char* buffer = NULL;
	unsigned int bufferSize = 256;
	bool success = false;
	while (!success)
	{
		delete [] buffer;
		buffer = new char[bufferSize];

		// Try to get the DLL filename.
		// This returns the number of chars copies on success, 0 otherwise.
		DWORD result = GetPrivateProfileString("Settings", name.c_str(), NULL, buffer, bufferSize, configFilename.c_str());
		success = result != bufferSize;
	}
	setting = std::string(buffer);
	delete [] buffer;
	return setting;
}

int getSettingInt(const string& name, int default)
{
	const string& configFilename = getConfigFilename();
	return GetPrivateProfileInt("Settings", name.c_str(), default, configFilename.c_str());
}

extern "C" __declspec(dllexport) const char* getName()
{
	static string name = getSetting("Name").c_str();
	return name.c_str();
}

extern "C" __declspec(dllexport) const char* getExt()
{
	static string extension;
	if (!extension.empty())
	{
		return extension.c_str();
	}
	const string& configFilename = getConfigFilename();
	string::size_type pos = configFilename.find("gfxcomp_") + 8;
	extension = configFilename.substr(pos);
	pos = extension.find('.');
	extension = extension.substr(0, pos);
	return extension.c_str();
}

void replace(string& haystack, const string& needle, const string& replacement)
{
	for (string::size_type pos = haystack.find(needle); pos != string::npos; pos = haystack.find(needle))
	{
		// Replace while we find it
		// This can go on forever with badly-chosen needles and replacements...
		haystack.replace(pos, needle.length(), replacement);
	}
}

int compress(uint8_t* source, uint32_t sourceLen, uint8_t* dest, uint32_t destLen)
{
	// We get a couple of temp filenames...
	char tempPathBuf[MAX_PATH];
	DWORD tempPathResult = GetTempPath(MAX_PATH, tempPathBuf);
	if (tempPathResult == 0 || tempPathResult >= MAX_PATH)
	{
		return -1;
	}
	ostringstream ss;
	ss << tempPathBuf << "gfxcomp_exe_temp_in_" << rand() << ".bin";
	string inFilename(ss.str());
	ss.str(string());
	ss << tempPathBuf << "gfxcomp_exe_temp_out_" << rand() << ".bin";
	string outFilename(ss.str());

	// We write the data to the first filename...
	// Since we're using Windows API for creating the process, let's use it for files too...
	HANDLE fIn = CreateFile(inFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (fIn == INVALID_HANDLE_VALUE)
	{
		return -1;
	}
	if (!WriteFile(fIn, source, sourceLen, NULL, NULL))
	{
		// Failed to write
		CloseHandle(fIn);
		return -1;
	}
	CloseHandle(fIn);

	// Then we get the command
	string command = getSetting("Command");
	// ...and substitute the placeholders in it
	replace(command, "%input%", inFilename);
	replace(command, "%output%", outFilename);

	// We need to clone it
	char* commandLine = _strdup(command.c_str());

	// Then we run it and wait for it to complete
	PROCESS_INFORMATION processInformation = {};
	STARTUPINFO startupInfo = {};
	BOOL created = CreateProcess(NULL, commandLine, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation);
	free(commandLine);

	if (!created)
	{
		// Failed to run the command
		return -1;
	}

	WaitForSingleObject(processInformation.hProcess, INFINITE);

	// We can delete the input file now
	DeleteFile(inFilename.c_str());

	// Then read in the output file
	HANDLE fOut = CreateFile(outFilename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (fOut == INVALID_HANDLE_VALUE)
	{
		return -1;
	}
	// Check the size
	DWORD fileSize = GetFileSize(fOut, NULL);
	if (fileSize > destLen)
	{
		// Dest buffer too small
		DeleteFile(outFilename.c_str());
		return 0;
	}
	// Read it in
	if (!ReadFile(fOut, dest, fileSize, NULL, NULL))
	{
		// Problem reading
		CloseHandle(fOut);
		DeleteFile(outFilename.c_str());
		return -1;
	}
	CloseHandle(fOut);
	DeleteFile(outFilename.c_str());

	return fileSize;
}

extern "C" __declspec(dllexport) int compressTiles(uint8_t* source, uint32_t numTiles, uint8_t* dest, uint32_t destLen)
{
	return compress(source, numTiles * 32, dest, destLen);
}

extern "C" __declspec(dllexport) int compressTilemap(uint8_t* source, uint32_t width, uint32_t height, uint8_t* dest, uint32_t destLen)
{
	return compress(source, width * height * 2, dest, destLen);
}
<commit_msg>Comment fix<commit_after>// This plugin looks at its own filename and uses that to find a config file that tells it how to work.
// The config file looks like this:
//
// [Settings]
// Name=Some name (for display purposes)
// Command=program.exe "%input%" "%output%"
//
// You can put anything in the Command, %input% and %output% will be substituted with filenames
// (possibly with spaces). Non-zero return codes will be interpreted as an error.
// TODO: allow stdin/stdout?

#pragma warning(push,3)
#include <windows.h>
#include <cstdint>
#include <string>
#include <sstream>
#pragma warning(pop)

using namespace ::std;

HINSTANCE g_hInstance;

extern "C" BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD, LPVOID)
{
	g_hInstance = hInst;
	return TRUE;
}

string getConfigFilename()
{
	static string filename;
	if (!filename.empty())
	{
		return filename;
	}

	char* buffer = NULL;
	unsigned int bufferSize = 256;
	bool success = false;
	while (!success && bufferSize < 1024*1024*1024)
	{
		delete [] buffer;
		buffer = new char[bufferSize];

		// Try to get the DLL filename.
		// This returns the number of chars copied on success, 0 otherwise.
		DWORD result = GetModuleFileName(g_hInstance, buffer, bufferSize);
		success = result != bufferSize;
		bufferSize *= 2;
	}
	filename = std::string(buffer);
	delete [] buffer;
	// We append .ini
	filename += ".ini";
	return filename;
}

string getSetting(const string& name)
{
	const std::string& configFilename = getConfigFilename();
	std::string setting;

	char* buffer = NULL;
	unsigned int bufferSize = 256;
	bool success = false;
	while (!success)
	{
		delete [] buffer;
		buffer = new char[bufferSize];

		// Try to get the setting value.
		// This returns the number of chars copied on success, 0 otherwise.
		DWORD result = GetPrivateProfileString("Settings", name.c_str(), NULL, buffer, bufferSize, configFilename.c_str());
		success = result != bufferSize;
	}
	setting = std::string(buffer);
	delete [] buffer;
	return setting;
}

int getSettingInt(const string& name, int default)
{
	const string& configFilename = getConfigFilename();
	return GetPrivateProfileInt("Settings", name.c_str(), default, configFilename.c_str());
}

extern "C" __declspec(dllexport) const char* getName()
{
	static string name = getSetting("Name").c_str();
	return name.c_str();
}

extern "C" __declspec(dllexport) const char* getExt()
{
	static string extension;
	if (!extension.empty())
	{
		return extension.c_str();
	}
	const string& configFilename = getConfigFilename();
	string::size_type pos = configFilename.find("gfxcomp_") + 8;
	extension = configFilename.substr(pos);
	pos = extension.find('.');
	extension = extension.substr(0, pos);
	return extension.c_str();
}

void replace(string& haystack, const string& needle, const string& replacement)
{
	for (string::size_type pos = haystack.find(needle); pos != string::npos; pos = haystack.find(needle))
	{
		// Replace while we find it
		// This can go on forever with badly-chosen needles and replacements...
		haystack.replace(pos, needle.length(), replacement);
	}
}

int compress(uint8_t* source, uint32_t sourceLen, uint8_t* dest, uint32_t destLen)
{
	// We get a couple of temp filenames...
	char tempPathBuf[MAX_PATH];
	DWORD tempPathResult = GetTempPath(MAX_PATH, tempPathBuf);
	if (tempPathResult == 0 || tempPathResult >= MAX_PATH)
	{
		return -1;
	}
	ostringstream ss;
	ss << tempPathBuf << "gfxcomp_exe_temp_in_" << rand() << ".bin";
	string inFilename(ss.str());
	ss.str(string());
	ss << tempPathBuf << "gfxcomp_exe_temp_out_" << rand() << ".bin";
	string outFilename(ss.str());

	// We write the data to the first filename...
	// Since we're using Windows API for creating the process, let's use it for files too...
	HANDLE fIn = CreateFile(inFilename.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (fIn == INVALID_HANDLE_VALUE)
	{
		return -1;
	}
	if (!WriteFile(fIn, source, sourceLen, NULL, NULL))
	{
		// Failed to write
		CloseHandle(fIn);
		return -1;
	}
	CloseHandle(fIn);

	// Then we get the command
	string command = getSetting("Command");
	// ...and substitute the placeholders in it
	replace(command, "%input%", inFilename);
	replace(command, "%output%", outFilename);

	// We need to clone it
	char* commandLine = _strdup(command.c_str());

	// Then we run it and wait for it to complete
	PROCESS_INFORMATION processInformation = {};
	STARTUPINFO startupInfo = {};
	BOOL created = CreateProcess(NULL, commandLine, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation);
	free(commandLine);

	if (!created)
	{
		// Failed to run the command
		return -1;
	}

	WaitForSingleObject(processInformation.hProcess, INFINITE);

	// We can delete the input file now
	DeleteFile(inFilename.c_str());

	// Then read in the output file
	HANDLE fOut = CreateFile(outFilename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (fOut == INVALID_HANDLE_VALUE)
	{
		return -1;
	}
	// Check the size
	DWORD fileSize = GetFileSize(fOut, NULL);
	if (fileSize > destLen)
	{
		// Dest buffer too small
		DeleteFile(outFilename.c_str());
		return 0;
	}
	// Read it in
	if (!ReadFile(fOut, dest, fileSize, NULL, NULL))
	{
		// Problem reading
		CloseHandle(fOut);
		DeleteFile(outFilename.c_str());
		return -1;
	}
	CloseHandle(fOut);
	DeleteFile(outFilename.c_str());

	return fileSize;
}

extern "C" __declspec(dllexport) int compressTiles(uint8_t* source, uint32_t numTiles, uint8_t* dest, uint32_t destLen)
{
	return compress(source, numTiles * 32, dest, destLen);
}

extern "C" __declspec(dllexport) int compressTilemap(uint8_t* source, uint32_t width, uint32_t height, uint8_t* dest, uint32_t destLen)
{
	return compress(source, width * height * 2, dest, destLen);
}
<|endoftext|>


<commit_before>#include "Halide.h"
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    const int size_x = 766;
    const int size_y = 311;

    {
        Func f, g, h, j;
        Var x, y;
        f(x, y) = x + y;
        g(x, y) = cast<float>(f(x, y) + f(x+1, y));
        h(x, y) = f(x, y) + g(x, y);

        Target target = get_jit_target_from_environment();
        if (target.has_gpu_feature()) {
            f.compute_root().gpu_tile(x, y, 1, 1).reorder_storage(y, x).debug_to_file("f.tmp");
            g.compute_root().gpu_tile(x, y, 1, 1).reorder_storage(y, x).debug_to_file("g.tmp");
            h.compute_root().gpu_tile(x, y, 1, 1).debug_to_file("h.tmp");
        } else {
            f.compute_root().reorder_storage(y, x).debug_to_file("f.tmp");
            g.compute_root().reorder_storage(y, x).debug_to_file("g.tmp");
            h.compute_root().debug_to_file("h.tmp");
        }

        Image<float> im = h.realize(size_x, size_y, target);
    }

    FILE *f = fopen("f.tmp", "rb");
    FILE *g = fopen("g.tmp", "rb");
    FILE *h = fopen("h.tmp", "rb");
    assert(f && g && h);

    int header[5];
    assert(fread((void *)(&header[0]), 4, 5, f) == 5);
    assert(header[0] == size_x+1);
    assert(header[1] == size_y);
    assert(header[2] == 1);
    assert(header[3] == 1);
    assert(header[4] == 7);

    std::vector<int32_t> f_data((size_x+1)*size_y);
    assert(fread((void *)(&f_data[0]), 4, (size_x+1)*size_y, f) == (size_x+1)*size_y);
    for (int y = 0; y < size_y; y++) {
        for (int x = 0; x < size_x+1; x++) {
            int32_t val = f_data[y*(size_x+1)+x];
            if (val != x+y) {
                printf("f_data[%d, %d] = %d instead of %d\n", x, y, val, x+y);
                return -1;
            }
        }
    }
    fclose(f);

    assert(fread((void *)(&header[0]), 4, 5, g) == 5);
    assert(header[0] == size_x);
    assert(header[1] == size_y);
    assert(header[2] == 1);
    assert(header[3] == 1);
    assert(header[4] == 0);

    std::vector<float> g_data(size_x*size_y);
    assert(fread((void *)(&g_data[0]), 4, size_x*size_y, g) == size_x*size_y);
    for (int y = 0; y < size_y; y++) {
        for (int x = 0; x < size_x; x++) {
            float val = g_data[y*size_x+x];
            float correct = (float)(f_data[y*(size_x+1)+x] + f_data[y*(size_x+1)+x+1]);
            if (val != correct) {
                printf("g_data[%d, %d] = %f instead of %f\n", x, y, val, correct);
                return -1;
            }
        }
    }
    fclose(g);

    assert(fread((void *)(&header[0]), 4, 5, h) == 5);
    assert(header[0] == size_x);
    assert(header[1] == size_y);
    assert(header[2] == 1);
    assert(header[3] == 1);
    assert(header[4] == 0);

    std::vector<float> h_data(size_x*size_y);
    assert(fread((void *)(&h_data[0]), 4, size_x*size_y, h) == size_x*size_y);
    for (int y = 0; y < size_y; y++) {
        for (int x = 0; x < size_x; x++) {
            float val = h_data[y*size_x+x];
            float correct = f_data[y*(size_x+1)+x] + g_data[y*size_x+x];
            if (val != correct) {
                printf("h_data[%d, %d] = %f instead of %f\n", x, y, val, correct);
                return -1;
            }
        }
    }
    fclose(h);

    printf("Success!\n");
    return 0;

}
<commit_msg>Fix debug_to_file_reorder<commit_after>#include "Halide.h"
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    const int size_x = 766;
    const int size_y = 311;

    {
        Func f, g, h, j;
        Var x, y;
        f(x, y) = x + y;
        g(x, y) = cast<float>(f(x, y) + f(x+1, y));
        h(x, y) = f(x, y) + g(x, y);

        Target target = get_jit_target_from_environment();
        if (target.has_gpu_feature()) {
            f.compute_root().gpu_tile(x, y, 1, 1).reorder_storage(y, x).debug_to_file("f2.tmp");
            g.compute_root().gpu_tile(x, y, 1, 1).reorder_storage(y, x).debug_to_file("g2.tmp");
            h.compute_root().gpu_tile(x, y, 1, 1).debug_to_file("h2.tmp");
        } else {
            f.compute_root().reorder_storage(y, x).debug_to_file("f2.tmp");
            g.compute_root().reorder_storage(y, x).debug_to_file("g2.tmp");
            h.compute_root().debug_to_file("h2.tmp");
        }

        Image<float> im = h.realize(size_x, size_y, target);
    }

    FILE *f = fopen("f2.tmp", "rb");
    FILE *g = fopen("g2.tmp", "rb");
    FILE *h = fopen("h2.tmp", "rb");
    assert(f && g && h);

    int header[5];
    assert(fread((void *)(&header[0]), 4, 5, f) == 5);
    assert(header[0] == size_x+1);
    assert(header[1] == size_y);
    assert(header[2] == 1);
    assert(header[3] == 1);
    assert(header[4] == 7);

    std::vector<int32_t> f_data((size_x+1)*size_y);
    assert(fread((void *)(&f_data[0]), 4, (size_x+1)*size_y, f) == (size_x+1)*size_y);
    for (int y = 0; y < size_y; y++) {
        for (int x = 0; x < size_x+1; x++) {
            int32_t val = f_data[y*(size_x+1)+x];
            if (val != x+y) {
                printf("f_data[%d, %d] = %d instead of %d\n", x, y, val, x+y);
                return -1;
            }
        }
    }
    fclose(f);

    assert(fread((void *)(&header[0]), 4, 5, g) == 5);
    assert(header[0] == size_x);
    assert(header[1] == size_y);
    assert(header[2] == 1);
    assert(header[3] == 1);
    assert(header[4] == 0);

    std::vector<float> g_data(size_x*size_y);
    assert(fread((void *)(&g_data[0]), 4, size_x*size_y, g) == size_x*size_y);
    for (int y = 0; y < size_y; y++) {
        for (int x = 0; x < size_x; x++) {
            float val = g_data[y*size_x+x];
            float correct = (float)(f_data[y*(size_x+1)+x] + f_data[y*(size_x+1)+x+1]);
            if (val != correct) {
                printf("g_data[%d, %d] = %f instead of %f\n", x, y, val, correct);
                return -1;
            }
        }
    }
    fclose(g);

    assert(fread((void *)(&header[0]), 4, 5, h) == 5);
    assert(header[0] == size_x);
    assert(header[1] == size_y);
    assert(header[2] == 1);
    assert(header[3] == 1);
    assert(header[4] == 0);

    std::vector<float> h_data(size_x*size_y);
    assert(fread((void *)(&h_data[0]), 4, size_x*size_y, h) == size_x*size_y);
    for (int y = 0; y < size_y; y++) {
        for (int x = 0; x < size_x; x++) {
            float val = h_data[y*size_x+x];
            float correct = f_data[y*(size_x+1)+x] + g_data[y*size_x+x];
            if (val != correct) {
                printf("h_data[%d, %d] = %f instead of %f\n", x, y, val, correct);
                return -1;
            }
        }
    }
    fclose(h);

    printf("Success!\n");
    return 0;

}
<|endoftext|>


<commit_before>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "IncrementalExecutor.h"
#include "IncrementalJIT.h"
#include "Threading.h"

#include "cling/Interpreter/Value.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/Basic/Diagnostic.h"

#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"

#ifdef LLVM_ON_WIN32
extern "C"
char *__unDName(char *demangled, const char *mangled, int out_len,
                void * (* pAlloc )(size_t), void (* pFree )(void *),
                unsigned short int flags);
#else
#include <cxxabi.h>
#endif

using namespace llvm;

namespace cling {

IncrementalExecutor::IncrementalExecutor(clang::DiagnosticsEngine& diags):
  m_CurrentAtExitModule(0)
#if 0
  : m_Diags(diags)
#endif
{

  // MSVC doesn't support m_AtExitFuncsSpinLock=ATOMIC_FLAG_INIT; in the class definition
  std::atomic_flag_clear( &m_AtExitFuncsSpinLock );

  // No need to protect this access of m_AtExitFuncs, since nobody
  // can use this object yet.
  m_AtExitFuncs.reserve(256);

  m_JIT.reset(new IncrementalJIT(*this, std::move(CreateHostTargetMachine())));
}

// Keep in source: ~unique_ptr<ClingJIT> needs ClingJIT
IncrementalExecutor::~IncrementalExecutor() {}

std::unique_ptr<TargetMachine>
  IncrementalExecutor::CreateHostTargetMachine() const {
  // TODO: make this configurable.
  Triple TheTriple(sys::getProcessTriple());
#ifdef _WIN32
  /*
	* MCJIT works on Windows, but currently only through ELF object format.
	*/
  TheTriple.setObjectFormat(llvm::Triple::ELF);
#endif
  std::string Error;
  const Target *TheTarget
    = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
  if (!TheTarget) {
    llvm::errs() << "cling::IncrementalExecutor: unable to find target:\n"
                 << Error;
  }

  std::string MCPU;
  std::string FeaturesStr;

  TargetOptions Options = TargetOptions();
  Options.NoFramePointerElim = 1;
  Options.JITEmitDebugInfo = 1;
  Reloc::Model RelocModel = Reloc::Default;
  CodeModel::Model CMModel = CodeModel::JITDefault;
  CodeGenOpt::Level OptLevel = CodeGenOpt::Less;

  std::unique_ptr<TargetMachine> TM;
  TM.reset(TheTarget->createTargetMachine(TheTriple.getTriple(),
                                          MCPU, FeaturesStr,
                                          Options,
                                          RelocModel, CMModel,
                                          OptLevel));
  return std::move(TM);
}

void IncrementalExecutor::shuttingDown() {
  // No need to protect this access, since hopefully there is no concurrent
  // shutdown request.
  for (size_t I = 0, N = m_AtExitFuncs.size(); I < N; ++I) {
    const CXAAtExitElement& AEE = m_AtExitFuncs[N - I - 1];
    (*AEE.m_Func)(AEE.m_Arg);
  }
}

void IncrementalExecutor::AddAtExitFunc(void (*func) (void*), void* arg) {
  // Register a CXAAtExit function
  cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock);
  m_AtExitFuncs.push_back(CXAAtExitElement(func, arg, m_CurrentAtExitModule));
}

void unresolvedSymbol()
{
  // throw exception?
  llvm::errs() << "IncrementalExecutor: calling unresolved symbol, "
    "see previous error message!\n";
}

void* IncrementalExecutor::HandleMissingFunction(const std::string& mangled_name)
{
  // Not found in the map, add the symbol in the list of unresolved symbols
  if (m_unresolvedSymbols.insert(mangled_name).second) {
    //llvm::errs() << "IncrementalExecutor: use of undefined symbol '"
    //             << mangled_name << "'!\n";
  }

  // Avoid "ISO C++ forbids casting between pointer-to-function and
  // pointer-to-object":
  return (void*)reinterpret_cast<size_t>(unresolvedSymbol);
}

void*
IncrementalExecutor::NotifyLazyFunctionCreators(const std::string& mangled_name)
{
  for (std::vector<LazyFunctionCreatorFunc_t>::iterator it
         = m_lazyFuncCreator.begin(), et = m_lazyFuncCreator.end();
       it != et; ++it) {
    void* ret = (void*)((LazyFunctionCreatorFunc_t)*it)(mangled_name);
    if (ret)
      return ret;
  }

  return HandleMissingFunction(mangled_name);
}

#if 0
// FIXME: employ to empty module dependencies *within* the *current* module.
static void
freeCallersOfUnresolvedSymbols(llvm::SmallVectorImpl<llvm::Function*>&
                               funcsToFree, llvm::ExecutionEngine* engine) {
  llvm::SmallPtrSet<llvm::Function*, 40> funcsToFreeUnique;
  for (size_t i = 0; i < funcsToFree.size(); ++i) {
    llvm::Function* func = funcsToFree[i];
    assert(func && "Cannot free NULL function");
    if (funcsToFreeUnique.insert(func).second) {
      for (llvm::Value::use_iterator IU = func->use_begin(),
             EU = func->use_end(); IU != EU; ++IU) {
        llvm::Instruction* instUser = llvm::dyn_cast<llvm::Instruction>(*IU);
        if (!instUser) continue;
        if (!instUser->getParent()) continue;
        if (llvm::Function* userFunc = instUser->getParent()->getParent())
          funcsToFree.push_back(userFunc);
      }
    }
  }
  for (llvm::SmallPtrSet<llvm::Function*, 40>::iterator
         I = funcsToFreeUnique.begin(), E = funcsToFreeUnique.end();
       I != E; ++I) {
    // This should force the JIT to recompile the function. But the stubs stay,
    // and the JIT reuses the stubs now pointing nowhere, i.e. without updating
    // the machine code address. Fix the JIT, or hope that MCJIT helps.
    //engine->freeMachineCodeForFunction(*I);
    engine->updateGlobalMapping(*I, 0);
  }
}
#endif

IncrementalExecutor::ExecutionResult
IncrementalExecutor::runStaticInitializersOnce(const Transaction& T) {
  llvm::Module* m = T.getModule();
  assert(m && "Module must not be null");

  // Set m_CurrentAtExitModule to the Module, unset to 0 once done.
  struct AtExitModuleSetterRAII {
    llvm::Module*& m_AEM;
    AtExitModuleSetterRAII(llvm::Module* M, llvm::Module*& AEM): m_AEM(AEM)
    { AEM = M; }
    ~AtExitModuleSetterRAII() { m_AEM = 0; }
  } DSOHandleSetter(m, m_CurrentAtExitModule);

  // We don't care whether something was unresolved before.
  m_unresolvedSymbols.clear();

  // check if there is any unresolved symbol in the list
  if (diagnoseUnresolvedSymbols("static initializers"))
    return kExeUnresolvedSymbols;

  llvm::GlobalVariable* GV
     = m->getGlobalVariable("llvm.global_ctors", true);
  // Nothing to do is good, too.
  if (!GV) return kExeSuccess;

  // Close similarity to
  // m_engine->runStaticConstructorsDestructors(false) aka
  // llvm::ExecutionEngine::runStaticConstructorsDestructors()
  // is intentional; we do an extra pass to check whether the JIT
  // managed to collect all the symbols needed by the niitializers.
  // Should be an array of '{ i32, void ()* }' structs.  The first value is
  // the init priority, which we ignore.
  llvm::ConstantArray *InitList
    = llvm::dyn_cast<llvm::ConstantArray>(GV->getInitializer());

  // We need to delete it here just in case we have recursive inits, otherwise
  // it will call inits multiple times.
  GV->eraseFromParent();

  if (InitList == 0)
    return kExeSuccess;

  SmallVector<Function*, 2> initFuncs;

  for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
    llvm::ConstantStruct *CS
      = llvm::dyn_cast<llvm::ConstantStruct>(InitList->getOperand(i));
    if (CS == 0) continue;

    llvm::Constant *FP = CS->getOperand(1);
    if (FP->isNullValue())
      continue;  // Found a sentinal value, ignore.

    // Strip off constant expression casts.
    if (llvm::ConstantExpr *CE = llvm::dyn_cast<llvm::ConstantExpr>(FP))
      if (CE->isCast())
        FP = CE->getOperand(0);

    // Execute the ctor/dtor function!
    if (llvm::Function *F = llvm::dyn_cast<llvm::Function>(FP)) {
      executeInit(F->getName());

      initFuncs.push_back(F);
      if (F->getName().startswith("_GLOBAL__sub_I__")) {
        BasicBlock& BB = F->getEntryBlock();
        for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I)
          if (CallInst* call = dyn_cast<CallInst>(I))
            initFuncs.push_back(call->getCalledFunction());
      }
    }
  }

  for (SmallVector<Function*,2>::iterator I = initFuncs.begin(),
         E = initFuncs.end(); I != E; ++I) {
    // Cleanup also the dangling init functions. They are in the form:
    // define internal void @_GLOBAL__I_aN() section "..."{
    // entry:
    //   call void @__cxx_global_var_init(N-1)()
    //   call void @__cxx_global_var_initM()
    //   ret void
    // }
    //
    // define internal void @__cxx_global_var_init(N-1)() section "..." {
    // entry:
    //   call void @_ZN7MyClassC1Ev(%struct.MyClass* @n)
    //   ret void
    // }

    // Erase __cxx_global_var_init(N-1)() first.
    (*I)->removeDeadConstantUsers();
    (*I)->eraseFromParent();
  }

  return kExeSuccess;
}

void IncrementalExecutor::runAndRemoveStaticDestructors(Transaction* T) {
  assert(T && "Must be set");
  // Collect all the dtors bound to this transaction.
  AtExitFunctions boundToT;

  {
    cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock);
    for (AtExitFunctions::iterator I = m_AtExitFuncs.begin();
         I != m_AtExitFuncs.end();)
      if (I->m_FromM == T->getModule()) {
        boundToT.push_back(*I);
        I = m_AtExitFuncs.erase(I);
      }
      else
        ++I;
  } // end of spin lock lifetime block.

  // 'Unload' the cxa_atexit entities.
  for (AtExitFunctions::reverse_iterator I = boundToT.rbegin(),
         E = boundToT.rend(); I != E; ++I) {
    const CXAAtExitElement& AEE = *I;
    (*AEE.m_Func)(AEE.m_Arg);
  }
}

void
IncrementalExecutor::installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp)
{
  m_lazyFuncCreator.push_back(fp);
}

bool
IncrementalExecutor::addSymbol(const char* symbolName,  void* symbolAddress) {
  void* actualAddress
    = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
  if (actualAddress)
    return false;

  llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolAddress);
  return true;
}

void* IncrementalExecutor::getAddressOfGlobal(llvm::StringRef symbolName,
                                              bool* fromJIT /*=0*/) {
  // Return a symbol's address, and whether it was jitted.
  void* address
    = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);

  // It's not from the JIT if it's in a dylib.
  if (fromJIT)
    *fromJIT = !address;

  if (!address)
    return (void*)m_JIT->getSymbolAddress(symbolName);

  return address;
}

void*
IncrementalExecutor::getPointerToGlobalFromJIT(const llvm::GlobalValue& GV) {
  // Get the function / variable pointer referenced by GV.

  // We don't care whether something was unresolved before.
  m_unresolvedSymbols.clear();

  void* addr = (void*)m_JIT->getSymbolAddress(GV.getName());

  if (diagnoseUnresolvedSymbols(GV.getName(), "symbol"))
    return 0;
  return addr;
}

bool IncrementalExecutor::diagnoseUnresolvedSymbols(llvm::StringRef trigger,
                                                    llvm::StringRef title) {
  if (m_unresolvedSymbols.empty())
    return false;

  llvm::SmallVector<llvm::Function*, 128> funcsToFree;
  for (std::set<std::string>::const_iterator i = m_unresolvedSymbols.begin(),
         e = m_unresolvedSymbols.end(); i != e; ++i) {
#if 0
    // FIXME: This causes a lot of test failures, for some reason it causes
    // the call to HandleMissingFunction to be elided.
    unsigned diagID = m_Diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
                                              "%0 unresolved while jitting %1");
    (void)diagID;
    //m_Diags.Report(diagID) << *i << funcname; // TODO: demangle the names.
#endif

    llvm::errs() << "IncrementalExecutor::executeFunction: symbol '" << *i
                 << "' unresolved while linking ";
    if (trigger.find(utils::Synthesize::UniquePrefix) != llvm::StringRef::npos)
      llvm::errs() << "[cling interface function]";
    else {
      if (!title.empty())
        llvm::errs() << title << " '";
      llvm::errs() << trigger;
      if (!title.empty())
        llvm::errs() << "'";
    }
    llvm::errs() << "!\n";

    // Be helpful, demangle!
    std::string demangledName;
    {
#ifndef LLVM_ON_WIN32
      int status = 0;
      char *demang = abi::__cxa_demangle(i->c_str(), 0, 0, &status);
      if (status == 0)
        demangledName = demang;
      free(demang);
#else
      if (char* demang = __unDName(0, i->c_str(), 0, malloc, free, 0)) {
        demangledName = demang;
        free(demang);
      }
#endif
    }
    if (!demangledName.empty()) {
       llvm::errs()
          << "You are probably missing the definition of "
          << demangledName << "\n"
          << "Maybe you need to load the corresponding shared library?\n";
    }

    //llvm::Function *ff = m_engine->FindFunctionNamed(i->c_str());
    // i could also reference a global variable, in which case ff == 0.
    //if (ff)
    //  funcsToFree.push_back(ff);
  }
  //freeCallersOfUnresolvedSymbols(funcsToFree, m_engine.get());
  m_unresolvedSymbols.clear();
  return true;
}

}// end namespace cling
<commit_msg>Silence *calling* unresolved symbols. Handing it out already complains.<commit_after>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "IncrementalExecutor.h"
#include "IncrementalJIT.h"
#include "Threading.h"

#include "cling/Interpreter/Value.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"

#include "clang/Basic/Diagnostic.h"

#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"

#ifdef LLVM_ON_WIN32
extern "C"
char *__unDName(char *demangled, const char *mangled, int out_len,
                void * (* pAlloc )(size_t), void (* pFree )(void *),
                unsigned short int flags);
#else
#include <cxxabi.h>
#endif

using namespace llvm;

namespace cling {

IncrementalExecutor::IncrementalExecutor(clang::DiagnosticsEngine& diags):
  m_CurrentAtExitModule(0)
#if 0
  : m_Diags(diags)
#endif
{

  // MSVC doesn't support m_AtExitFuncsSpinLock=ATOMIC_FLAG_INIT; in the class definition
  std::atomic_flag_clear( &m_AtExitFuncsSpinLock );

  // No need to protect this access of m_AtExitFuncs, since nobody
  // can use this object yet.
  m_AtExitFuncs.reserve(256);

  m_JIT.reset(new IncrementalJIT(*this, std::move(CreateHostTargetMachine())));
}

// Keep in source: ~unique_ptr<ClingJIT> needs ClingJIT
IncrementalExecutor::~IncrementalExecutor() {}

std::unique_ptr<TargetMachine>
  IncrementalExecutor::CreateHostTargetMachine() const {
  // TODO: make this configurable.
  Triple TheTriple(sys::getProcessTriple());
#ifdef _WIN32
  /*
	* MCJIT works on Windows, but currently only through ELF object format.
	*/
  TheTriple.setObjectFormat(llvm::Triple::ELF);
#endif
  std::string Error;
  const Target *TheTarget
    = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
  if (!TheTarget) {
    llvm::errs() << "cling::IncrementalExecutor: unable to find target:\n"
                 << Error;
  }

  std::string MCPU;
  std::string FeaturesStr;

  TargetOptions Options = TargetOptions();
  Options.NoFramePointerElim = 1;
  Options.JITEmitDebugInfo = 1;
  Reloc::Model RelocModel = Reloc::Default;
  CodeModel::Model CMModel = CodeModel::JITDefault;
  CodeGenOpt::Level OptLevel = CodeGenOpt::Less;

  std::unique_ptr<TargetMachine> TM;
  TM.reset(TheTarget->createTargetMachine(TheTriple.getTriple(),
                                          MCPU, FeaturesStr,
                                          Options,
                                          RelocModel, CMModel,
                                          OptLevel));
  return std::move(TM);
}

void IncrementalExecutor::shuttingDown() {
  // No need to protect this access, since hopefully there is no concurrent
  // shutdown request.
  for (size_t I = 0, N = m_AtExitFuncs.size(); I < N; ++I) {
    const CXAAtExitElement& AEE = m_AtExitFuncs[N - I - 1];
    (*AEE.m_Func)(AEE.m_Arg);
  }
}

void IncrementalExecutor::AddAtExitFunc(void (*func) (void*), void* arg) {
  // Register a CXAAtExit function
  cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock);
  m_AtExitFuncs.push_back(CXAAtExitElement(func, arg, m_CurrentAtExitModule));
}

void unresolvedSymbol()
{
  // This might get called recursively, or a billion of times. Do not generate
  // useless output; unresolvedSymbol() is always handed out with an error
  // message - that's enough.
  //llvm::errs() << "IncrementalExecutor: calling unresolved symbol, "
  //  "see previous error message!\n";

  // throw exception instead?
}

void* IncrementalExecutor::HandleMissingFunction(const std::string& mangled_name)
{
  // Not found in the map, add the symbol in the list of unresolved symbols
  if (m_unresolvedSymbols.insert(mangled_name).second) {
    //llvm::errs() << "IncrementalExecutor: use of undefined symbol '"
    //             << mangled_name << "'!\n";
  }

  // Avoid "ISO C++ forbids casting between pointer-to-function and
  // pointer-to-object":
  return (void*)reinterpret_cast<size_t>(unresolvedSymbol);
}

void*
IncrementalExecutor::NotifyLazyFunctionCreators(const std::string& mangled_name)
{
  for (std::vector<LazyFunctionCreatorFunc_t>::iterator it
         = m_lazyFuncCreator.begin(), et = m_lazyFuncCreator.end();
       it != et; ++it) {
    void* ret = (void*)((LazyFunctionCreatorFunc_t)*it)(mangled_name);
    if (ret)
      return ret;
  }

  return HandleMissingFunction(mangled_name);
}

#if 0
// FIXME: employ to empty module dependencies *within* the *current* module.
static void
freeCallersOfUnresolvedSymbols(llvm::SmallVectorImpl<llvm::Function*>&
                               funcsToFree, llvm::ExecutionEngine* engine) {
  llvm::SmallPtrSet<llvm::Function*, 40> funcsToFreeUnique;
  for (size_t i = 0; i < funcsToFree.size(); ++i) {
    llvm::Function* func = funcsToFree[i];
    assert(func && "Cannot free NULL function");
    if (funcsToFreeUnique.insert(func).second) {
      for (llvm::Value::use_iterator IU = func->use_begin(),
             EU = func->use_end(); IU != EU; ++IU) {
        llvm::Instruction* instUser = llvm::dyn_cast<llvm::Instruction>(*IU);
        if (!instUser) continue;
        if (!instUser->getParent()) continue;
        if (llvm::Function* userFunc = instUser->getParent()->getParent())
          funcsToFree.push_back(userFunc);
      }
    }
  }
  for (llvm::SmallPtrSet<llvm::Function*, 40>::iterator
         I = funcsToFreeUnique.begin(), E = funcsToFreeUnique.end();
       I != E; ++I) {
    // This should force the JIT to recompile the function. But the stubs stay,
    // and the JIT reuses the stubs now pointing nowhere, i.e. without updating
    // the machine code address. Fix the JIT, or hope that MCJIT helps.
    //engine->freeMachineCodeForFunction(*I);
    engine->updateGlobalMapping(*I, 0);
  }
}
#endif

IncrementalExecutor::ExecutionResult
IncrementalExecutor::runStaticInitializersOnce(const Transaction& T) {
  llvm::Module* m = T.getModule();
  assert(m && "Module must not be null");

  // Set m_CurrentAtExitModule to the Module, unset to 0 once done.
  struct AtExitModuleSetterRAII {
    llvm::Module*& m_AEM;
    AtExitModuleSetterRAII(llvm::Module* M, llvm::Module*& AEM): m_AEM(AEM)
    { AEM = M; }
    ~AtExitModuleSetterRAII() { m_AEM = 0; }
  } DSOHandleSetter(m, m_CurrentAtExitModule);

  // We don't care whether something was unresolved before.
  m_unresolvedSymbols.clear();

  // check if there is any unresolved symbol in the list
  if (diagnoseUnresolvedSymbols("static initializers"))
    return kExeUnresolvedSymbols;

  llvm::GlobalVariable* GV
     = m->getGlobalVariable("llvm.global_ctors", true);
  // Nothing to do is good, too.
  if (!GV) return kExeSuccess;

  // Close similarity to
  // m_engine->runStaticConstructorsDestructors(false) aka
  // llvm::ExecutionEngine::runStaticConstructorsDestructors()
  // is intentional; we do an extra pass to check whether the JIT
  // managed to collect all the symbols needed by the niitializers.
  // Should be an array of '{ i32, void ()* }' structs.  The first value is
  // the init priority, which we ignore.
  llvm::ConstantArray *InitList
    = llvm::dyn_cast<llvm::ConstantArray>(GV->getInitializer());

  // We need to delete it here just in case we have recursive inits, otherwise
  // it will call inits multiple times.
  GV->eraseFromParent();

  if (InitList == 0)
    return kExeSuccess;

  SmallVector<Function*, 2> initFuncs;

  for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
    llvm::ConstantStruct *CS
      = llvm::dyn_cast<llvm::ConstantStruct>(InitList->getOperand(i));
    if (CS == 0) continue;

    llvm::Constant *FP = CS->getOperand(1);
    if (FP->isNullValue())
      continue;  // Found a sentinal value, ignore.

    // Strip off constant expression casts.
    if (llvm::ConstantExpr *CE = llvm::dyn_cast<llvm::ConstantExpr>(FP))
      if (CE->isCast())
        FP = CE->getOperand(0);

    // Execute the ctor/dtor function!
    if (llvm::Function *F = llvm::dyn_cast<llvm::Function>(FP)) {
      executeInit(F->getName());

      initFuncs.push_back(F);
      if (F->getName().startswith("_GLOBAL__sub_I__")) {
        BasicBlock& BB = F->getEntryBlock();
        for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I)
          if (CallInst* call = dyn_cast<CallInst>(I))
            initFuncs.push_back(call->getCalledFunction());
      }
    }
  }

  for (SmallVector<Function*,2>::iterator I = initFuncs.begin(),
         E = initFuncs.end(); I != E; ++I) {
    // Cleanup also the dangling init functions. They are in the form:
    // define internal void @_GLOBAL__I_aN() section "..."{
    // entry:
    //   call void @__cxx_global_var_init(N-1)()
    //   call void @__cxx_global_var_initM()
    //   ret void
    // }
    //
    // define internal void @__cxx_global_var_init(N-1)() section "..." {
    // entry:
    //   call void @_ZN7MyClassC1Ev(%struct.MyClass* @n)
    //   ret void
    // }

    // Erase __cxx_global_var_init(N-1)() first.
    (*I)->removeDeadConstantUsers();
    (*I)->eraseFromParent();
  }

  return kExeSuccess;
}

void IncrementalExecutor::runAndRemoveStaticDestructors(Transaction* T) {
  assert(T && "Must be set");
  // Collect all the dtors bound to this transaction.
  AtExitFunctions boundToT;

  {
    cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock);
    for (AtExitFunctions::iterator I = m_AtExitFuncs.begin();
         I != m_AtExitFuncs.end();)
      if (I->m_FromM == T->getModule()) {
        boundToT.push_back(*I);
        I = m_AtExitFuncs.erase(I);
      }
      else
        ++I;
  } // end of spin lock lifetime block.

  // 'Unload' the cxa_atexit entities.
  for (AtExitFunctions::reverse_iterator I = boundToT.rbegin(),
         E = boundToT.rend(); I != E; ++I) {
    const CXAAtExitElement& AEE = *I;
    (*AEE.m_Func)(AEE.m_Arg);
  }
}

void
IncrementalExecutor::installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp)
{
  m_lazyFuncCreator.push_back(fp);
}

bool
IncrementalExecutor::addSymbol(const char* symbolName,  void* symbolAddress) {
  void* actualAddress
    = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
  if (actualAddress)
    return false;

  llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolAddress);
  return true;
}

void* IncrementalExecutor::getAddressOfGlobal(llvm::StringRef symbolName,
                                              bool* fromJIT /*=0*/) {
  // Return a symbol's address, and whether it was jitted.
  void* address
    = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);

  // It's not from the JIT if it's in a dylib.
  if (fromJIT)
    *fromJIT = !address;

  if (!address)
    return (void*)m_JIT->getSymbolAddress(symbolName);

  return address;
}

void*
IncrementalExecutor::getPointerToGlobalFromJIT(const llvm::GlobalValue& GV) {
  // Get the function / variable pointer referenced by GV.

  // We don't care whether something was unresolved before.
  m_unresolvedSymbols.clear();

  void* addr = (void*)m_JIT->getSymbolAddress(GV.getName());

  if (diagnoseUnresolvedSymbols(GV.getName(), "symbol"))
    return 0;
  return addr;
}

bool IncrementalExecutor::diagnoseUnresolvedSymbols(llvm::StringRef trigger,
                                                    llvm::StringRef title) {
  if (m_unresolvedSymbols.empty())
    return false;

  llvm::SmallVector<llvm::Function*, 128> funcsToFree;
  for (std::set<std::string>::const_iterator i = m_unresolvedSymbols.begin(),
         e = m_unresolvedSymbols.end(); i != e; ++i) {
#if 0
    // FIXME: This causes a lot of test failures, for some reason it causes
    // the call to HandleMissingFunction to be elided.
    unsigned diagID = m_Diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
                                              "%0 unresolved while jitting %1");
    (void)diagID;
    //m_Diags.Report(diagID) << *i << funcname; // TODO: demangle the names.
#endif

    llvm::errs() << "IncrementalExecutor::executeFunction: symbol '" << *i
                 << "' unresolved while linking ";
    if (trigger.find(utils::Synthesize::UniquePrefix) != llvm::StringRef::npos)
      llvm::errs() << "[cling interface function]";
    else {
      if (!title.empty())
        llvm::errs() << title << " '";
      llvm::errs() << trigger;
      if (!title.empty())
        llvm::errs() << "'";
    }
    llvm::errs() << "!\n";

    // Be helpful, demangle!
    std::string demangledName;
    {
#ifndef LLVM_ON_WIN32
      int status = 0;
      char *demang = abi::__cxa_demangle(i->c_str(), 0, 0, &status);
      if (status == 0)
        demangledName = demang;
      free(demang);
#else
      if (char* demang = __unDName(0, i->c_str(), 0, malloc, free, 0)) {
        demangledName = demang;
        free(demang);
      }
#endif
    }
    if (!demangledName.empty()) {
       llvm::errs()
          << "You are probably missing the definition of "
          << demangledName << "\n"
          << "Maybe you need to load the corresponding shared library?\n";
    }

    //llvm::Function *ff = m_engine->FindFunctionNamed(i->c_str());
    // i could also reference a global variable, in which case ff == 0.
    //if (ff)
    //  funcsToFree.push_back(ff);
  }
  //freeCallersOfUnresolvedSymbols(funcsToFree, m_engine.get());
  m_unresolvedSymbols.clear();
  return true;
}

}// end namespace cling
<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 Andrew Sutton
// All rights reserved

#include "equivalence.hpp"
#include "ast.hpp"

#include <typeindex>

namespace banjo
{

bool is_equivalent(Type const&, Type const&);
bool is_equivalent(Void_type const&, Void_type const&);
bool is_equivalent(Boolean_type const&, Boolean_type const&);
bool is_equivalent(Integer_type const&, Integer_type const&);
bool is_equivalent(Float_type const&, Float_type const&);
bool is_equivalent(Auto_type const&, Auto_type const&);
bool is_equivalent(Decltype_type const&, Decltype_type const&);
bool is_equivalent(Declauto_type const&, Declauto_type const&);
bool is_equivalent(Function_type const&, Function_type const&);
bool is_equivalent(Qualified_type const&, Qualified_type const&);
bool is_equivalent(Reference_type const&, Reference_type const&);
bool is_equivalent(Pointer_type const&, Pointer_type const&);
bool is_equivalent(Array_type const&, Array_type const&);
bool is_equivalent(Sequence_type const&, Sequence_type const&);
bool is_equivalent(User_defined_type const&, User_defined_type const&);

template<typename T>
inline bool
is_equivalent(List<T> const& a, List<T> const& b)
{
  auto cmp = [](T const& a, T const& b) {
    return is_equivalent(a, b);
  };
  return std::equal(a.begin(), a.end(), b.begin(), b.end(), cmp);
}

// Returns true if the types a and b are equivalent.
//
// TODO: Finish implementing this function.
bool
is_equivalent(Type const& t1, Type const& t2)
{
  struct fn
  {
    Type const& t2;
    bool operator()(Void_type const& t1) const         { return is_equivalent(t1, cast<Void_type>(t2)); }
    bool operator()(Boolean_type const& t1) const      { return is_equivalent(t1, cast<Boolean_type>(t2)); }
    bool operator()(Integer_type const& t1) const      { return is_equivalent(t1, cast<Integer_type>(t2)); }
    bool operator()(Float_type const& t1) const        { return is_equivalent(t1, cast<Float_type>(t2)); }
    bool operator()(Auto_type const& t1) const         { return is_equivalent(t1, cast<Auto_type>(t2)); }
    bool operator()(Decltype_type const& t1) const     { return is_equivalent(t1, cast<Decltype_type>(t2)); }
    bool operator()(Declauto_type const& t1) const     { return is_equivalent(t1, cast<Declauto_type>(t2)); }
    bool operator()(Function_type const& t1) const     { return is_equivalent(t1, cast<Function_type>(t2)); }
    bool operator()(Qualified_type const& t1) const    { return is_equivalent(t1, cast<Qualified_type>(t2)); }
    bool operator()(Reference_type const& t1) const    { return is_equivalent(t1, cast<Reference_type>(t2)); }
    bool operator()(Pointer_type const& t1) const      { return is_equivalent(t1, cast<Pointer_type>(t2)); }
    bool operator()(Array_type const& t1) const        { return is_equivalent(t1, cast<Array_type>(t2)); }
    bool operator()(Sequence_type const& t1) const     { return is_equivalent(t1, cast<Sequence_type>(t2)); }
    bool operator()(User_defined_type const& t1) const { return is_equivalent(t1, cast<User_defined_type>(t2)); }
    bool operator()(Typename_type const& t1) const     { lingo_unimplemented(); }
  };

  // The same objects represent the same types.
  if (&t1 == &t2)
    return true;

  // Types of different kinds are not the same.
  std::type_index ti1 = typeid(t1);
  std::type_index ti2 = typeid(t2);
  if (ti1 != ti2)
    return false;

  // Find a comparison of the types.
  return apply(t1, fn{t2});
}

bool
is_equivalent(Void_type const&, Void_type const&)
{
  return true;
}

bool
is_equivalent(Boolean_type const&, Boolean_type const&)
{
  return true;
}

bool
is_equivalent(Integer_type const& t1, Integer_type const& t2)
{
  return t1.is_signed() == t2.is_signed() && t1.precision() == t2.precision();
}

bool
is_equivalent(Float_type const& t1, Float_type const& t2)
{
  return t1.precision() == t2.precision();
}

// TODO: When are two placeholder types equivalent?
bool
is_equivalent(Auto_type const&, Auto_type const&)
{
  return false;
}

bool
is_equivalent(Decltype_type const& a, Decltype_type const& b)
{
  lingo_unimplemented();
}

// TODO: When are placeholder types equivalent?
bool
is_equivalent(Declauto_type const& t1, Declauto_type const& t2)
{
  return false;
}

bool
is_equivalent(Function_type const& t1, Function_type const& t2)
{
  return is_equivalent(t1.parameter_types(), t2.parameter_types())
      && is_equivalent(t1.return_type(), t2.return_type());
}

bool
is_equivalent(Qualified_type const& t1, Qualified_type const& t2)
{
  return t1.qualifier() == t2.qualifier() && is_equivalent(t1.type(), t2.type());
}

bool
is_equivalent(Reference_type const& t1, Reference_type const& t2)
{
  return is_equivalent(t1.type(), t2.type());
}

bool
is_equivalent(Pointer_type const& t1, Pointer_type const& t2)
{
  return is_equivalent(t1.type(), t2.type());
}

// TODO: The extent of the arrays must be equivalent.
bool
is_equivalent(Array_type const&, Array_type const&)
{
  lingo_unimplemented();
}

bool
is_equivalent(Sequence_type const& t1, Sequence_type const& t2)
{
  return is_equivalent(t1.type(), t2.type());
}

// TODO: This isn't quite right. It depends on declaration chains.
bool
is_equivalent(User_defined_type const& t1, User_defined_type const& t2)
{
  return &t1.declaration() == &t2.declaration();
}

} // namespace banjo
<commit_msg>working on are same<commit_after>// Copyright (c) 2015-2016 Andrew Sutton
// All rights reserved

#include "equivalence.hpp"
#include "ast.hpp"

#include <typeindex>

namespace banjo
{

bool is_equivalent(Type const&, Type const&);
bool is_equivalent(Void_type const&, Void_type const&);
bool is_equivalent(Boolean_type const&, Boolean_type const&);
bool is_equivalent(Integer_type const&, Integer_type const&);
bool is_equivalent(Float_type const&, Float_type const&);
bool is_equivalent(Auto_type const&, Auto_type const&);
bool is_equivalent(Decltype_type const&, Decltype_type const&);
bool is_equivalent(Declauto_type const&, Declauto_type const&);
bool is_equivalent(Function_type const&, Function_type const&);
bool is_equivalent(Qualified_type const&, Qualified_type const&);
bool is_equivalent(Reference_type const&, Reference_type const&);
bool is_equivalent(Pointer_type const&, Pointer_type const&);
bool is_equivalent(Array_type const&, Array_type const&);
bool is_equivalent(Sequence_type const&, Sequence_type const&);
bool is_equivalent(User_defined_type const&, User_defined_type const&);

bool are_same(Name const&, Name const&);

template<typename T>
inline bool
is_equivalent(List<T> const& a, List<T> const& b)
{
  auto cmp = [](T const& a, T const& b) {
    return is_equivalent(a, b);
  };
  return std::equal(a.begin(), a.end(), b.begin(), b.end(), cmp);
}

// Returns true if the types a and b are equivalent.
//
// TODO: Finish implementing this function.
bool
is_equivalent(Type const& t1, Type const& t2)
{
  struct fn
  {
    Type const& t2;
    bool operator()(Void_type const& t1) const         { return is_equivalent(t1, cast<Void_type>(t2)); }
    bool operator()(Boolean_type const& t1) const      { return is_equivalent(t1, cast<Boolean_type>(t2)); }
    bool operator()(Integer_type const& t1) const      { return is_equivalent(t1, cast<Integer_type>(t2)); }
    bool operator()(Float_type const& t1) const        { return is_equivalent(t1, cast<Float_type>(t2)); }
    bool operator()(Auto_type const& t1) const         { return is_equivalent(t1, cast<Auto_type>(t2)); }
    bool operator()(Decltype_type const& t1) const     { return is_equivalent(t1, cast<Decltype_type>(t2)); }
    bool operator()(Declauto_type const& t1) const     { return is_equivalent(t1, cast<Declauto_type>(t2)); }
    bool operator()(Function_type const& t1) const     { return is_equivalent(t1, cast<Function_type>(t2)); }
    bool operator()(Qualified_type const& t1) const    { return is_equivalent(t1, cast<Qualified_type>(t2)); }
    bool operator()(Reference_type const& t1) const    { return is_equivalent(t1, cast<Reference_type>(t2)); }
    bool operator()(Pointer_type const& t1) const      { return is_equivalent(t1, cast<Pointer_type>(t2)); }
    bool operator()(Array_type const& t1) const        { return is_equivalent(t1, cast<Array_type>(t2)); }
    bool operator()(Sequence_type const& t1) const     { return is_equivalent(t1, cast<Sequence_type>(t2)); }
    bool operator()(User_defined_type const& t1) const { return is_equivalent(t1, cast<User_defined_type>(t2)); }
    bool operator()(Typename_type const& t1) const     { lingo_unimplemented(); }
  };

  // The same objects represent the same types.
  if (&t1 == &t2)
    return true;

  // Types of different kinds are not the same.
  std::type_index ti1 = typeid(t1);
  std::type_index ti2 = typeid(t2);
  if (ti1 != ti2)
    return false;

  // Find a comparison of the types.
  return apply(t1, fn{t2});
}

bool are_Same(Name const& n1, Name const& n2){

  // Need to check scope

  //they are identifiers composed of the same character sequence
  if (auto id1 = as<Simple_id>(&n1)){
    if (auto id2 = as<Simple_id>(&n2)){
      return id1->first->spelling() == id2->first->spelling();
    }
  }

  // they are operator-function-ids formed with the same operator

  // they are conversion-function-ids formed with the same type

  // they are template-ids that refer to the same class or function
  if (auto id1 = as<Template_id>(&n1)){
    if (Template_id *id2 = as<Template_id>(&n2)){

    }
  }
  // they are the names of literal operators (13.5.8) formed with the same literal suffix identifier.

  return false;
}

bool
is_equivalent(Void_type const&, Void_type const&)
{
  return true;
}

bool
is_equivalent(Boolean_type const&, Boolean_type const&)
{
  return true;
}

bool
is_equivalent(Integer_type const& t1, Integer_type const& t2)
{
  return t1.is_signed() == t2.is_signed() && t1.precision() == t2.precision();
}

bool
is_equivalent(Float_type const& t1, Float_type const& t2)
{
  return t1.precision() == t2.precision();
}

// TODO: When are two placeholder types equivalent?
bool
is_equivalent(Auto_type const&, Auto_type const&)
{
  return false;
}

bool
is_equivalent(Decltype_type const& a, Decltype_type const& b)
{
  lingo_unimplemented();
}

// TODO: When are placeholder types equivalent?
bool
is_equivalent(Declauto_type const& t1, Declauto_type const& t2)
{
  return false;
}

bool
is_equivalent(Function_type const& t1, Function_type const& t2)
{
  return is_equivalent(t1.parameter_types(), t2.parameter_types())
      && is_equivalent(t1.return_type(), t2.return_type());
}

bool
is_equivalent(Qualified_type const& t1, Qualified_type const& t2)
{
  return t1.qualifier() == t2.qualifier() && is_equivalent(t1.type(), t2.type());
}

bool
is_equivalent(Reference_type const& t1, Reference_type const& t2)
{
  return is_equivalent(t1.type(), t2.type());
}

bool
is_equivalent(Pointer_type const& t1, Pointer_type const& t2)
{
  return is_equivalent(t1.type(), t2.type());
}

// TODO: The extent of the arrays must be equivalent.
bool
is_equivalent(Array_type const&, Array_type const&)
{
  lingo_unimplemented();
}

bool
is_equivalent(Sequence_type const& t1, Sequence_type const& t2)
{
  return is_equivalent(t1.type(), t2.type());
}

// TODO: This isn't quite right. It depends on declaration chains.
bool
is_equivalent(User_defined_type const& t1, User_defined_type const& t2)
{
  return &t1.declaration() == &t2.declaration();
}

} // namespace banjo
<|endoftext|>


<commit_before><commit_msg>Using bounding box helper functions<commit_after><|endoftext|>