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

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

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

#include "mitkLevelWindowManager.h"
#include <itkCommand.h>
#include "mitkDataStorage.h"
#include "mitkNodePredicateBase.h"
#include "mitkNodePredicateProperty.h"
#include "mitkNodePredicateDataType.h"
#include "mitkNodePredicateAnd.h"
#include "mitkNodePredicateOr.h"
#include "mitkNodePredicateNot.h"
#include "mitkProperties.h"
#include "mitkMessage.h"

mitk::LevelWindowManager::LevelWindowManager()
: m_DataStorage(NULL), m_LevelWindowProperty(NULL), m_AutoTopMost(true),
  m_IsObserverTagSet(false), m_CurrentImage(NULL),m_IsPropertyModifiedTagSet(false)
{
}

mitk::LevelWindowManager::~LevelWindowManager()
{
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
    m_DataStorage = NULL;
  }
  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  for( std::map<unsigned long, mitk::BaseProperty::Pointer>::iterator iter = m_PropObserverToNode.begin(); iter != m_PropObserverToNode.end(); iter++ ) {
    (*iter).second->RemoveObserver((*iter).first);
  }
  for( std::map<unsigned long, mitk::BaseProperty::Pointer>::iterator iter = m_PropObserverToNode2.begin(); iter != m_PropObserverToNode2.end(); iter++ ) {
    (*iter).second->RemoveObserver((*iter).first);
  }
}

void mitk::LevelWindowManager::SetDataStorage( mitk::DataStorage* ds )
{
  if (ds == NULL)
    return;

  /* remove listeners of old DataStorage */
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
  }
  /* register listener for new DataStorage */
  m_DataStorage = ds;  // register
  m_DataStorage->AddNodeEvent.AddListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
  m_DataStorage->RemoveNodeEvent.AddListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
  this->DataStorageChanged(); // update us with new DataStorage
}

void mitk::LevelWindowManager::OnPropertyModified(const itk::EventObject& )
{
  Modified();
}

void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const mitk::DataNode* removedNode)
{
  m_AutoTopMost = autoTopMost;
  if (m_AutoTopMost == false)
    return;

  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  /* search topmost image */
  if (m_DataStorage.IsNull())
  {
    itkExceptionMacro("DataStorage not set");
  }
  int maxLayer = itk::NumericTraits<int>::min();
  m_LevelWindowProperty = NULL;

  mitk::DataNode::Pointer topLevelNode;

  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull() || (removedNode != NULL && node == removedNode))
      continue;

    node->SetBoolProperty( "imageForLevelWindow", false );

    if (node->IsVisible(NULL) == false)
      continue;

    int layer = 0;
    node->GetIntProperty("layer", layer);
    if ( layer < maxLayer )
      continue;
    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;
    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    topLevelNode = node;

    maxLayer = layer;
  }

  if (topLevelNode.IsNotNull())
  {
    topLevelNode->SetBoolProperty( "imageForLevelWindow", true );
  }

  this->SetLevelWindowProperty( m_LevelWindowProperty );

  if ( m_LevelWindowProperty.IsNull() )
  {
    Modified();
  }
  // else SetLevelWindowProperty will call Modified();
}

// sets an specific LevelWindowProperty, all changes will affect the image belonging to this property.
// sets m_AutoTopMost to false
void mitk::LevelWindowManager::SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty)
{
  if (levelWindowProperty.IsNull())
    return;

  if (m_IsPropertyModifiedTagSet)  // remove listener for old property
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  m_LevelWindowProperty = levelWindowProperty;

  itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();  // register listener for new property
  command->SetCallbackFunction(this, &LevelWindowManager::OnPropertyModified);
  m_PropertyModifiedTag = m_LevelWindowProperty->AddObserver( itk::ModifiedEvent(), command );
  m_IsPropertyModifiedTagSet = true;
  m_AutoTopMost = false;

  /* search image than belongs to the property */
  mitk::NodePredicateProperty::Pointer p = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
  mitk::DataNode* n = m_DataStorage->GetNode(p);
  if (n == NULL)
  {
    itkExceptionMacro("No Image in DataStorage that belongs to LevelWindow property " << m_LevelWindowProperty);
  }
  m_CurrentImage = dynamic_cast<mitk::Image*>(n->GetData());
  n->SetBoolProperty( "imageForLevelWindow", true );
  this->Modified();
}

// returns the current mitkLevelWindowProperty object from the image that is affected by changes
mitk::LevelWindowProperty::Pointer mitk::LevelWindowManager::GetLevelWindowProperty()
{
  return m_LevelWindowProperty;
}

// returns Level/Window values for the current image
const mitk::LevelWindow& mitk::LevelWindowManager::GetLevelWindow()
{
  if (m_LevelWindowProperty.IsNotNull())
    return m_LevelWindowProperty->GetLevelWindow();
  else
  {
    itkExceptionMacro("No LevelWindow available!");
  }
}

// sets new Level/Window values and informs all listeners about changes
void mitk::LevelWindowManager::SetLevelWindow(const mitk::LevelWindow& levelWindow)
{
  if (m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->SetLevelWindow(levelWindow);
  }
  this->Modified();
}

void mitk::LevelWindowManager::DataStorageChanged( const mitk::DataNode* )
{
  this->DataStorageRemovedNode();
}
void mitk::LevelWindowManager::DataStorageRemovedNode( const mitk::DataNode* removedNode )
{
  /* remove old observers */
  for (ObserverToPropertyMap::iterator iter = m_PropObserverToNode.begin(); iter != m_PropObserverToNode.end(); iter++ )
    (*iter).second->RemoveObserver((*iter).first);
  m_PropObserverToNode.clear();

  for (ObserverToPropertyMap::iterator iter = m_PropObserverToNode2.begin(); iter != m_PropObserverToNode2.end(); iter++ )
    (*iter).second->RemoveObserver((*iter).first);
  m_PropObserverToNode2.clear();

  if (m_DataStorage.IsNull())
  {
    itkExceptionMacro("DataStorage not set");
  }

  /* listen to changes  in visible property of all images */

  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    if (it->Value().IsNull())
      continue;
    /* register listener for changes in visible property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command->SetCallbackFunction(this, &LevelWindowManager::Update);
    m_PropObserverToNode[it->Value()->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command )] = it->Value()->GetProperty("visible");
  }

  /* listen to changes  in layer property of all images */

  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    if (it->Value().IsNull())
      continue;
    /* register listener for changes in layer property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command2 = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command2->SetCallbackFunction(this, &LevelWindowManager::Update);
    m_PropObserverToNode2[it->Value()->GetProperty("layer")->AddObserver( itk::ModifiedEvent(), command2 )] = it->Value()->GetProperty("layer");
  }

  /* search image than belongs to the property */
  if (m_LevelWindowProperty.IsNull())
    SetAutoTopMostImage(true, removedNode);
  else
  {
    mitk::NodePredicateProperty::Pointer p2 = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
    mitk::DataNode* n = m_DataStorage->GetNode(p2);
    if (n == NULL || m_AutoTopMost) // if node was deleted, change our behaviour to AutoTopMost, if AutoTopMost is true change level window to topmost node
      SetAutoTopMostImage(true, removedNode);
   }
}

mitk::DataStorage* mitk::LevelWindowManager::GetDataStorage()
{
  return m_DataStorage.GetPointer();
}

// true if changes on slider or line-edits will affect always the topmost layer image
bool mitk::LevelWindowManager::isAutoTopMost()
{
  return m_AutoTopMost;
}

void mitk::LevelWindowManager::Update(const itk::EventObject&)  // visible property of a image has changed
{
  if (m_AutoTopMost)
  {
    SetAutoTopMostImage(true);
    return;
  }
  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull())
      continue;

    node->SetBoolProperty( "imageForLevelWindow", false );

    if (node->IsVisible(NULL) == false)
      continue;

    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;
    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    node->SetBoolProperty( "imageForLevelWindow", true );
    if (m_LevelWindowProperty.IsNull() && m_LevelWindowProperty.GetPointer() == levelWindowProperty) // we found our m_LevelWindowProperty
    {
      return;
    }
  }
  Modified();
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::LevelWindowManager::GetRelevantNodes()
{
  if (m_DataStorage.IsNull())
    return mitk::DataStorage::SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New());  // return empty set

  mitk::BoolProperty::Pointer trueProp = mitk::BoolProperty::New(true);
  mitk::NodePredicateProperty::Pointer notBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(false));
  mitk::NodePredicateProperty::Pointer hasLevelWindow = mitk::NodePredicateProperty::New("levelwindow", NULL);

  mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image");
  mitk::NodePredicateDataType::Pointer isDImage = mitk::NodePredicateDataType::New("DiffusionImage");
  mitk::NodePredicateDataType::Pointer isTImage = mitk::NodePredicateDataType::New("TensorImage");
  mitk::NodePredicateDataType::Pointer isQImage = mitk::NodePredicateDataType::New("QBallImage");
  mitk::NodePredicateOr::Pointer predicateTypes = mitk::NodePredicateOr::New();
  predicateTypes->AddPredicate(isImage);
  predicateTypes->AddPredicate(isDImage);
  predicateTypes->AddPredicate(isTImage);
  predicateTypes->AddPredicate(isQImage);

  mitk::NodePredicateAnd::Pointer predicate = mitk::NodePredicateAnd::New();
  predicate->AddPredicate(notBinary);
  predicate->AddPredicate(hasLevelWindow);
  predicate->AddPredicate(predicateTypes);

  mitk::DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset( predicate );
  return relevantNodes;
}

mitk::Image* mitk::LevelWindowManager::GetCurrentImage()
{
  return m_CurrentImage;
}
<commit_msg>Temporary fix for AutoTopMost in LevelWindowManager<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

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

#include "mitkLevelWindowManager.h"
#include <itkCommand.h>
#include "mitkDataStorage.h"
#include "mitkNodePredicateBase.h"
#include "mitkNodePredicateProperty.h"
#include "mitkNodePredicateDataType.h"
#include "mitkNodePredicateAnd.h"
#include "mitkNodePredicateOr.h"
#include "mitkNodePredicateNot.h"
#include "mitkProperties.h"
#include "mitkMessage.h"

mitk::LevelWindowManager::LevelWindowManager()
: m_DataStorage(NULL), m_LevelWindowProperty(NULL), m_AutoTopMost(true),
  m_IsObserverTagSet(false), m_CurrentImage(NULL),m_IsPropertyModifiedTagSet(false)
{
}

mitk::LevelWindowManager::~LevelWindowManager()
{
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
    m_DataStorage = NULL;
  }
  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  for( std::map<unsigned long, mitk::BaseProperty::Pointer>::iterator iter = m_PropObserverToNode.begin(); iter != m_PropObserverToNode.end(); iter++ ) {
    (*iter).second->RemoveObserver((*iter).first);
  }
  for( std::map<unsigned long, mitk::BaseProperty::Pointer>::iterator iter = m_PropObserverToNode2.begin(); iter != m_PropObserverToNode2.end(); iter++ ) {
    (*iter).second->RemoveObserver((*iter).first);
  }
}

void mitk::LevelWindowManager::SetDataStorage( mitk::DataStorage* ds )
{
  if (ds == NULL)
    return;

  /* remove listeners of old DataStorage */
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
  }
  /* register listener for new DataStorage */
  m_DataStorage = ds;  // register
  m_DataStorage->AddNodeEvent.AddListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
  m_DataStorage->RemoveNodeEvent.AddListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
  this->DataStorageChanged(); // update us with new DataStorage
}

void mitk::LevelWindowManager::OnPropertyModified(const itk::EventObject& )
{
  Modified();
}

void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const mitk::DataNode* removedNode)
{
  m_AutoTopMost = autoTopMost;
  if (m_AutoTopMost == false)
    return;

  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  /* search topmost image */
  if (m_DataStorage.IsNull())
  {
    itkExceptionMacro("DataStorage not set");
  }
  int maxLayer = itk::NumericTraits<int>::min();
  m_LevelWindowProperty = NULL;

  mitk::DataNode::Pointer topLevelNode;

  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull() || (removedNode != NULL && node == removedNode))
      continue;

    node->SetBoolProperty( "imageForLevelWindow", false );

    if (node->IsVisible(NULL) == false)
      continue;

    int layer = 0;
    node->GetIntProperty("layer", layer);
    if ( layer < maxLayer )
      continue;
    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;
    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    topLevelNode = node;

    maxLayer = layer;
  }

  if (topLevelNode.IsNotNull())
  {
    topLevelNode->SetBoolProperty( "imageForLevelWindow", true );
  }

  this->SetLevelWindowProperty( m_LevelWindowProperty );

  if ( m_LevelWindowProperty.IsNull() )
  {
    Modified();
  }
  // else SetLevelWindowProperty will call Modified();
}

// sets an specific LevelWindowProperty, all changes will affect the image belonging to this property.
// sets m_AutoTopMost to false
void mitk::LevelWindowManager::SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty)
{
  if (levelWindowProperty.IsNull())
    return;

  if (m_IsPropertyModifiedTagSet)  // remove listener for old property
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  m_LevelWindowProperty = levelWindowProperty;

  itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();  // register listener for new property
  command->SetCallbackFunction(this, &LevelWindowManager::OnPropertyModified);
  m_PropertyModifiedTag = m_LevelWindowProperty->AddObserver( itk::ModifiedEvent(), command );
  m_IsPropertyModifiedTagSet = true;

  /* search image than belongs to the property */
  mitk::NodePredicateProperty::Pointer p = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
  mitk::DataNode* n = m_DataStorage->GetNode(p);
  if (n == NULL)
  {
    itkExceptionMacro("No Image in DataStorage that belongs to LevelWindow property " << m_LevelWindowProperty);
  }
  m_CurrentImage = dynamic_cast<mitk::Image*>(n->GetData());
  n->SetBoolProperty( "imageForLevelWindow", true );
  this->Modified();
}

// returns the current mitkLevelWindowProperty object from the image that is affected by changes
mitk::LevelWindowProperty::Pointer mitk::LevelWindowManager::GetLevelWindowProperty()
{
  return m_LevelWindowProperty;
}

// returns Level/Window values for the current image
const mitk::LevelWindow& mitk::LevelWindowManager::GetLevelWindow()
{
  if (m_LevelWindowProperty.IsNotNull())
    return m_LevelWindowProperty->GetLevelWindow();
  else
  {
    itkExceptionMacro("No LevelWindow available!");
  }
}

// sets new Level/Window values and informs all listeners about changes
void mitk::LevelWindowManager::SetLevelWindow(const mitk::LevelWindow& levelWindow)
{
  if (m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->SetLevelWindow(levelWindow);
  }
  this->Modified();
}

void mitk::LevelWindowManager::DataStorageChanged( const mitk::DataNode* )
{
  this->DataStorageRemovedNode();
}
void mitk::LevelWindowManager::DataStorageRemovedNode( const mitk::DataNode* removedNode )
{
  /* remove old observers */
  for (ObserverToPropertyMap::iterator iter = m_PropObserverToNode.begin(); iter != m_PropObserverToNode.end(); iter++ )
    (*iter).second->RemoveObserver((*iter).first);
  m_PropObserverToNode.clear();

  for (ObserverToPropertyMap::iterator iter = m_PropObserverToNode2.begin(); iter != m_PropObserverToNode2.end(); iter++ )
    (*iter).second->RemoveObserver((*iter).first);
  m_PropObserverToNode2.clear();

  if (m_DataStorage.IsNull())
  {
    itkExceptionMacro("DataStorage not set");
  }

  /* listen to changes  in visible property of all images */

  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    if (it->Value().IsNull())
      continue;
    /* register listener for changes in visible property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command->SetCallbackFunction(this, &LevelWindowManager::Update);
    m_PropObserverToNode[it->Value()->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command )] = it->Value()->GetProperty("visible");
  }

  /* listen to changes  in layer property of all images */

  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    if (it->Value().IsNull())
      continue;
    /* register listener for changes in layer property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command2 = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command2->SetCallbackFunction(this, &LevelWindowManager::Update);
    m_PropObserverToNode2[it->Value()->GetProperty("layer")->AddObserver( itk::ModifiedEvent(), command2 )] = it->Value()->GetProperty("layer");
  }

  /* search image than belongs to the property */
  if (m_LevelWindowProperty.IsNull())
    SetAutoTopMostImage(true, removedNode);
  else
  {
    mitk::NodePredicateProperty::Pointer p2 = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
    mitk::DataNode* n = m_DataStorage->GetNode(p2);
    if (n == NULL || m_AutoTopMost) // if node was deleted, change our behaviour to AutoTopMost, if AutoTopMost is true change level window to topmost node
      SetAutoTopMostImage(true, removedNode);
   }
}

mitk::DataStorage* mitk::LevelWindowManager::GetDataStorage()
{
  return m_DataStorage.GetPointer();
}

// true if changes on slider or line-edits will affect always the topmost layer image
bool mitk::LevelWindowManager::isAutoTopMost()
{
  return m_AutoTopMost;
}

void mitk::LevelWindowManager::Update(const itk::EventObject&)  // visible property of a image has changed
{
  if (m_AutoTopMost)
  {
    SetAutoTopMostImage(true);
    return;
  }
  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull())
      continue;

    node->SetBoolProperty( "imageForLevelWindow", false );

    if (node->IsVisible(NULL) == false)
      continue;

    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;
    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    node->SetBoolProperty( "imageForLevelWindow", true );
    if (m_LevelWindowProperty.IsNull() && m_LevelWindowProperty.GetPointer() == levelWindowProperty) // we found our m_LevelWindowProperty
    {
      return;
    }
  }
  Modified();
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::LevelWindowManager::GetRelevantNodes()
{
  if (m_DataStorage.IsNull())
    return mitk::DataStorage::SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New());  // return empty set

  mitk::BoolProperty::Pointer trueProp = mitk::BoolProperty::New(true);
  mitk::NodePredicateProperty::Pointer notBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(false));
  mitk::NodePredicateProperty::Pointer hasLevelWindow = mitk::NodePredicateProperty::New("levelwindow", NULL);

  mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image");
  mitk::NodePredicateDataType::Pointer isDImage = mitk::NodePredicateDataType::New("DiffusionImage");
  mitk::NodePredicateDataType::Pointer isTImage = mitk::NodePredicateDataType::New("TensorImage");
  mitk::NodePredicateDataType::Pointer isQImage = mitk::NodePredicateDataType::New("QBallImage");
  mitk::NodePredicateOr::Pointer predicateTypes = mitk::NodePredicateOr::New();
  predicateTypes->AddPredicate(isImage);
  predicateTypes->AddPredicate(isDImage);
  predicateTypes->AddPredicate(isTImage);
  predicateTypes->AddPredicate(isQImage);

  mitk::NodePredicateAnd::Pointer predicate = mitk::NodePredicateAnd::New();
  predicate->AddPredicate(notBinary);
  predicate->AddPredicate(hasLevelWindow);
  predicate->AddPredicate(predicateTypes);

  mitk::DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset( predicate );
  return relevantNodes;
}

mitk::Image* mitk::LevelWindowManager::GetCurrentImage()
{
  return m_CurrentImage;
}
<|endoftext|>


<commit_before>#include "compile-time-strings.hpp"
#include <cassert>

struct EMPTY {
	constexpr static const char* str() {
		return "";
	}
};

struct Hello {
	constexpr static const char* str() {
		return "Hello ";
	}
};

struct World {
	constexpr static const char* str() {
		return "World";
	}
};

struct Exclamation {
	constexpr static const char* str() {
		return "!";
	}
};

int main() {
	using E = ctstring::ctstring<EMPTY>;
	using H = ctstring::ctstring<Hello>;
	using W = ctstring::ctstring<World>;
	using HW = ctstring::concat<H, W>;
	using X = ctstring::concat<H, W, ctstring::ctstring<Exclamation>>;
	using C0 = ctstring::concat<>;

	assert(E::size == 0);
	assert(E::string() == "");

	assert(H::size == 6);
	assert(H::string() == "Hello ");

	assert(W::size == 5);
	assert(W::string() == "World");

	assert(HW::size == 11);
	assert(HW::string() == "Hello World");

	assert(X::size == 12);
	assert(X::string() == "Hello World!");

	assert(C0::size == 0);
	assert(C0::string() == "");
}
<commit_msg>compile-time-strings: Re-structure tests<commit_after>#include "compile-time-strings.hpp"
#include <cassert>

struct EMPTY {
	constexpr static const char* str() {
		return "";
	}
};

struct Hello {
	constexpr static const char* str() {
		return "Hello ";
	}
};

struct World {
	constexpr static const char* str() {
		return "World";
	}
};

struct Exclamation {
	constexpr static const char* str() {
		return "!";
	}
};

using E = ctstring::ctstring<EMPTY>;
using H = ctstring::ctstring<Hello>;
using W = ctstring::ctstring<World>;

void testBasics() {
	assert(E::size == 0);
	assert(E::string() == "");

	assert(H::size == 6);
	assert(H::string() == "Hello ");

	assert(W::size == 5);
	assert(W::string() == "World");
}

void testConcat() {
	using HW = ctstring::concat<H, W>;
	using X = ctstring::concat<H, W, ctstring::ctstring<Exclamation>>;
	using C0 = ctstring::concat<>;

	assert(HW::size == 11);
	assert(HW::string() == "Hello World");

	assert(X::size == 12);
	assert(X::string() == "Hello World!");

	assert(C0::size == 0);
	assert(C0::string() == "");
}

int main() {
	testBasics();
	testConcat();
}
<|endoftext|>


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

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/c/ops.h"

#include "tensorflow/c/tf_status_helper.h"
#include "tensorflow/core/framework/common_shape_fns.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_def_builder.h"
#include "tensorflow/core/framework/shape_inference.h"

using ::tensorflow::DataType;
using ::tensorflow::OpDef;
using ::tensorflow::OpDefBuilder;
using ::tensorflow::OpDeprecation;
using ::tensorflow::OpShapeInferenceFn;
using ::tensorflow::Set_TF_Status_from_Status;
using ::tensorflow::Status;
using ::tensorflow::shape_inference::DimensionHandle;
using ::tensorflow::shape_inference::InferenceContext;
using ::tensorflow::shape_inference::ShapeHandle;

TF_OpDefinitionBuilder* TF_NewOpDefinitionBuilder(const char* op_name) {
  auto* result = new OpDefBuilder(op_name);
  return reinterpret_cast<TF_OpDefinitionBuilder*>(result);
}

void TF_DeleteOpDefinitionBuilder(TF_OpDefinitionBuilder* builder) {
  delete reinterpret_cast<OpDefBuilder*>(builder);
}

void TF_OpDefinitionBuilderAddInput(TF_OpDefinitionBuilder* builder,
                                    const char* input_spec) {
  reinterpret_cast<OpDefBuilder*>(builder)->Input(input_spec);
}

void TF_OpDefinitionBuilderAddOutput(TF_OpDefinitionBuilder* builder,
                                     const char* output_spec) {
  reinterpret_cast<OpDefBuilder*>(builder)->Output(output_spec);
}

#define DEFINE_BUILDER_BOOL_SETTER(func_name)                             \
  void TF_OpDefinitionBuilder##func_name(TF_OpDefinitionBuilder* builder, \
                                         bool arg_name) {                 \
    reinterpret_cast<OpDefBuilder*>(builder)->func_name();                \
  }

DEFINE_BUILDER_BOOL_SETTER(SetIsCommutative)
DEFINE_BUILDER_BOOL_SETTER(SetIsAggregate)
DEFINE_BUILDER_BOOL_SETTER(SetIsStateful)
DEFINE_BUILDER_BOOL_SETTER(SetAllowsUninitializedInput)

void TF_OpDefinitionBuilderAddAttr(TF_OpDefinitionBuilder* builder,
                                   const char* attr_spec) {
  reinterpret_cast<OpDefBuilder*>(builder)->Attr(attr_spec);
}

void TF_OpDefinitionBuilderDeprecated(TF_OpDefinitionBuilder* builder,
                                      int version, const char* explanation) {
  reinterpret_cast<OpDefBuilder*>(builder)->Deprecated(version, explanation);
}

void TF_RegisterOpDefinition(TF_OpDefinitionBuilder* builder,
                             TF_Status* status) {
  auto* cc_builder = reinterpret_cast<OpDefBuilder*>(builder);
  TF_SetStatus(status, TF_OK, "");
  ::tensorflow::OpRegistry::Global()->Register(
      [cc_builder](::tensorflow::OpRegistrationData* op_reg_data) -> Status {
        Status result = cc_builder->Finalize(op_reg_data);
        delete cc_builder;
        return result;
      });
}

void TF_OpDefinitionBuilderSetShapeInferenceFunction(
    TF_OpDefinitionBuilder* builder,
    void (*shape_inference_func)(TF_ShapeInferenceContext* ctx,
                                 TF_Status* status)) {
  auto* cc_builder = reinterpret_cast<OpDefBuilder*>(builder);
  cc_builder->SetShapeFn(
      [shape_inference_func](InferenceContext* ctx) -> tensorflow::Status {
        TF_Status* c_status = TF_NewStatus();
        auto c_ctx = reinterpret_cast<TF_ShapeInferenceContext*>(ctx);
        shape_inference_func(c_ctx, c_status);
        tensorflow::Status result = ::tensorflow::StatusFromTF_Status(c_status);
        TF_DeleteStatus(c_status);
        return result;
      });
}

TF_ShapeHandle* TF_NewShapeHandle() {
  return reinterpret_cast<TF_ShapeHandle*>(new ShapeHandle);
}

TF_ShapeHandle* TF_ShapeInferenceContextScalar(TF_ShapeInferenceContext* ctx) {
  auto* handle = new ShapeHandle;
  *handle = reinterpret_cast<InferenceContext*>(ctx)->Scalar();
  return reinterpret_cast<TF_ShapeHandle*>(handle);
}

TF_ShapeHandle* TF_ShapeInferenceContextVectorFromSize(
    TF_ShapeInferenceContext* ctx, size_t size) {
  auto* handle = new ShapeHandle;
  *handle = reinterpret_cast<InferenceContext*>(ctx)->Vector(size);
  return reinterpret_cast<TF_ShapeHandle*>(handle);
}

void TF_ShapeInferenceContextConcatenateShapes(TF_ShapeInferenceContext* ctx,
                                               TF_ShapeHandle* first,
                                               TF_ShapeHandle* second,
                                               TF_ShapeHandle* result,
                                               TF_Status* status) {
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  Status s = cc_ctx->Concatenate(*reinterpret_cast<ShapeHandle*>(first),
                                 *reinterpret_cast<ShapeHandle*>(second),
                                 reinterpret_cast<ShapeHandle*>(result));
  Set_TF_Status_from_Status(status, s);
}

TF_DimensionHandle* TF_NewDimensionHandle() {
  return reinterpret_cast<TF_DimensionHandle*>(new DimensionHandle);
}

int64_t TF_ShapeInferenceContextNumInputs(TF_ShapeInferenceContext* ctx) {
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  return cc_ctx->num_inputs();
}

void TF_ShapeInferenceContextGetInput(TF_ShapeInferenceContext* ctx, int i,
                                      TF_ShapeHandle* handle,
                                      TF_Status* status) {
  TF_SetStatus(status, TF_OK, "");
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  if (0 < i || i >= cc_ctx->num_inputs()) {
    TF_SetStatus(status, TF_INVALID_ARGUMENT, "input index out of range");
  }
  if (TF_GetCode(status) == TF_OK) {
    auto* cc_result = reinterpret_cast<ShapeHandle*>(handle);
    *cc_result = cc_ctx->input(i);
  }
}

int TF_ShapeInferenceContextRankKnown(TF_ShapeInferenceContext* ctx,
                                      TF_ShapeHandle* handle) {
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  return cc_ctx->RankKnown(*reinterpret_cast<ShapeHandle*>(handle));
}

void TF_ShapeInferenceContextSetOutput(TF_ShapeInferenceContext* ctx, int i,
                                       TF_ShapeHandle* handle,
                                       TF_Status* status) {
  TF_SetStatus(status, TF_OK, "");
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  if (0 < i || i >= cc_ctx->num_outputs()) {
    TF_SetStatus(status, TF_INVALID_ARGUMENT, "output index out of range");
  }
  if (TF_GetCode(status) == TF_OK) {
    cc_ctx->set_output(i, *(reinterpret_cast<ShapeHandle*>(handle)));
  }
}

void TF_DeleteShapeHandle(TF_ShapeHandle* handle) {
  if (handle == nullptr) {
    return;
  }

  delete reinterpret_cast<ShapeHandle*>(handle);
}

void TF_DeleteDimensionHandle(TF_DimensionHandle* handle) {
  if (handle == nullptr) {
    return;
  }

  delete reinterpret_cast<DimensionHandle*>(handle);
}

#define DEFINE_TF_GETATTR(func, c_type, cc_type)                         \
  void TF_ShapeInferenceContext_GetAttr##func(                           \
      TF_ShapeInferenceContext* ctx, const char* attr_name, c_type* val, \
      TF_Status* status) {                                               \
    TF_SetStatus(status, TF_OK, "");                                     \
    cc_type v;                                                           \
    auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);             \
    Status s = cc_ctx->GetAttr(attr_name, &v);                           \
    Set_TF_Status_from_Status(status, s);                                \
    if (s.ok()) {                                                        \
      *val = static_cast<c_type>(v);                                     \
    }                                                                    \
  }

DEFINE_TF_GETATTR(Type, TF_DataType, tensorflow::DataType)

#define DEFINE_RANK_FUNC(func_name)                                        \
  void TF_ShapeInferenceContext##func_name(                                \
      TF_ShapeInferenceContext* ctx, TF_ShapeHandle* handle, int64_t rank, \
      TF_ShapeHandle* result, TF_Status* status) {                         \
    auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);               \
    auto* cc_handle = reinterpret_cast<ShapeHandle*>(handle);              \
    auto* cc_result = reinterpret_cast<ShapeHandle*>(result);              \
    Status s = cc_ctx->func_name(*cc_handle, rank, cc_result);             \
    Set_TF_Status_from_Status(status, s);                                  \
  }

DEFINE_RANK_FUNC(WithRank)
DEFINE_RANK_FUNC(WithRankAtLeast)
DEFINE_RANK_FUNC(WithRankAtMost)

int64_t TF_ShapeInferenceContextRank(TF_ShapeInferenceContext* ctx,
                                     TF_ShapeHandle* handle) {
  return reinterpret_cast<InferenceContext*>(ctx)->Rank(
      *reinterpret_cast<ShapeHandle*>(handle));
}

void TF_ShapeInferenceContextDim(TF_ShapeInferenceContext* ctx,
                                 TF_ShapeHandle* shape_handle, int64_t i,
                                 TF_DimensionHandle* result) {
  int64_t rank = TF_ShapeInferenceContextRank(ctx, shape_handle);
  auto* cc_result = reinterpret_cast<DimensionHandle*>(result);

  if (i < -rank || i >= rank) {
    *cc_result = DimensionHandle();
    return;
  }

  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  auto* cc_shape_handle = reinterpret_cast<ShapeHandle*>(shape_handle);
  *cc_result = cc_ctx->Dim(*cc_shape_handle, i);
}

int TF_DimensionHandleValueKnown(TF_DimensionHandle* dim_handle) {
  return InferenceContext::ValueKnown(
      *reinterpret_cast<DimensionHandle*>(dim_handle));
}

void TF_ShapeInferenceContextSetUnknownShape(TF_ShapeInferenceContext* ctx,
                                             TF_Status* status) {
  Status s = ::tensorflow::shape_inference::UnknownShape(
      reinterpret_cast<InferenceContext*>(ctx));
  Set_TF_Status_from_Status(status, s);
}

void TF_ShapeInferenceContextSubshape(TF_ShapeInferenceContext* ctx,
                                      TF_ShapeHandle* shape_handle,
                                      int64_t start, int64_t end,
                                      TF_ShapeHandle* result,
                                      TF_Status* status) {
  TF_SetStatus(status, TF_OK, "");
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  auto* cc_result = reinterpret_cast<ShapeHandle*>(result);
  Status s = cc_ctx->Subshape(*reinterpret_cast<ShapeHandle*>(shape_handle),
                              start, end, cc_result);
  Set_TF_Status_from_Status(status, s);
}

int64_t TF_DimensionHandleValue(TF_DimensionHandle* dim_handle) {
  return InferenceContext::Value(
      *reinterpret_cast<DimensionHandle*>(dim_handle));
}
<commit_msg>Fix out of range index error.<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/c/ops.h"

#include "tensorflow/c/tf_status_helper.h"
#include "tensorflow/core/framework/common_shape_fns.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_def_builder.h"
#include "tensorflow/core/framework/shape_inference.h"

using ::tensorflow::DataType;
using ::tensorflow::OpDef;
using ::tensorflow::OpDefBuilder;
using ::tensorflow::OpDeprecation;
using ::tensorflow::OpShapeInferenceFn;
using ::tensorflow::Set_TF_Status_from_Status;
using ::tensorflow::Status;
using ::tensorflow::shape_inference::DimensionHandle;
using ::tensorflow::shape_inference::InferenceContext;
using ::tensorflow::shape_inference::ShapeHandle;

TF_OpDefinitionBuilder* TF_NewOpDefinitionBuilder(const char* op_name) {
  auto* result = new OpDefBuilder(op_name);
  return reinterpret_cast<TF_OpDefinitionBuilder*>(result);
}

void TF_DeleteOpDefinitionBuilder(TF_OpDefinitionBuilder* builder) {
  delete reinterpret_cast<OpDefBuilder*>(builder);
}

void TF_OpDefinitionBuilderAddInput(TF_OpDefinitionBuilder* builder,
                                    const char* input_spec) {
  reinterpret_cast<OpDefBuilder*>(builder)->Input(input_spec);
}

void TF_OpDefinitionBuilderAddOutput(TF_OpDefinitionBuilder* builder,
                                     const char* output_spec) {
  reinterpret_cast<OpDefBuilder*>(builder)->Output(output_spec);
}

#define DEFINE_BUILDER_BOOL_SETTER(func_name)                             \
  void TF_OpDefinitionBuilder##func_name(TF_OpDefinitionBuilder* builder, \
                                         bool arg_name) {                 \
    reinterpret_cast<OpDefBuilder*>(builder)->func_name();                \
  }

DEFINE_BUILDER_BOOL_SETTER(SetIsCommutative)
DEFINE_BUILDER_BOOL_SETTER(SetIsAggregate)
DEFINE_BUILDER_BOOL_SETTER(SetIsStateful)
DEFINE_BUILDER_BOOL_SETTER(SetAllowsUninitializedInput)

void TF_OpDefinitionBuilderAddAttr(TF_OpDefinitionBuilder* builder,
                                   const char* attr_spec) {
  reinterpret_cast<OpDefBuilder*>(builder)->Attr(attr_spec);
}

void TF_OpDefinitionBuilderDeprecated(TF_OpDefinitionBuilder* builder,
                                      int version, const char* explanation) {
  reinterpret_cast<OpDefBuilder*>(builder)->Deprecated(version, explanation);
}

void TF_RegisterOpDefinition(TF_OpDefinitionBuilder* builder,
                             TF_Status* status) {
  auto* cc_builder = reinterpret_cast<OpDefBuilder*>(builder);
  TF_SetStatus(status, TF_OK, "");
  ::tensorflow::OpRegistry::Global()->Register(
      [cc_builder](::tensorflow::OpRegistrationData* op_reg_data) -> Status {
        Status result = cc_builder->Finalize(op_reg_data);
        delete cc_builder;
        return result;
      });
}

void TF_OpDefinitionBuilderSetShapeInferenceFunction(
    TF_OpDefinitionBuilder* builder,
    void (*shape_inference_func)(TF_ShapeInferenceContext* ctx,
                                 TF_Status* status)) {
  auto* cc_builder = reinterpret_cast<OpDefBuilder*>(builder);
  cc_builder->SetShapeFn(
      [shape_inference_func](InferenceContext* ctx) -> tensorflow::Status {
        TF_Status* c_status = TF_NewStatus();
        auto c_ctx = reinterpret_cast<TF_ShapeInferenceContext*>(ctx);
        shape_inference_func(c_ctx, c_status);
        tensorflow::Status result = ::tensorflow::StatusFromTF_Status(c_status);
        TF_DeleteStatus(c_status);
        return result;
      });
}

TF_ShapeHandle* TF_NewShapeHandle() {
  return reinterpret_cast<TF_ShapeHandle*>(new ShapeHandle);
}

TF_ShapeHandle* TF_ShapeInferenceContextScalar(TF_ShapeInferenceContext* ctx) {
  auto* handle = new ShapeHandle;
  *handle = reinterpret_cast<InferenceContext*>(ctx)->Scalar();
  return reinterpret_cast<TF_ShapeHandle*>(handle);
}

TF_ShapeHandle* TF_ShapeInferenceContextVectorFromSize(
    TF_ShapeInferenceContext* ctx, size_t size) {
  auto* handle = new ShapeHandle;
  *handle = reinterpret_cast<InferenceContext*>(ctx)->Vector(size);
  return reinterpret_cast<TF_ShapeHandle*>(handle);
}

void TF_ShapeInferenceContextConcatenateShapes(TF_ShapeInferenceContext* ctx,
                                               TF_ShapeHandle* first,
                                               TF_ShapeHandle* second,
                                               TF_ShapeHandle* result,
                                               TF_Status* status) {
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  Status s = cc_ctx->Concatenate(*reinterpret_cast<ShapeHandle*>(first),
                                 *reinterpret_cast<ShapeHandle*>(second),
                                 reinterpret_cast<ShapeHandle*>(result));
  Set_TF_Status_from_Status(status, s);
}

TF_DimensionHandle* TF_NewDimensionHandle() {
  return reinterpret_cast<TF_DimensionHandle*>(new DimensionHandle);
}

int64_t TF_ShapeInferenceContextNumInputs(TF_ShapeInferenceContext* ctx) {
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  return cc_ctx->num_inputs();
}

void TF_ShapeInferenceContextGetInput(TF_ShapeInferenceContext* ctx, int i,
                                      TF_ShapeHandle* handle,
                                      TF_Status* status) {
  TF_SetStatus(status, TF_OK, "");
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  if (i < 0 || i >= cc_ctx->num_inputs()) {
    TF_SetStatus(status, TF_INVALID_ARGUMENT, "input index out of range");
  }
  if (TF_GetCode(status) == TF_OK) {
    auto* cc_result = reinterpret_cast<ShapeHandle*>(handle);
    *cc_result = cc_ctx->input(i);
  }
}

int TF_ShapeInferenceContextRankKnown(TF_ShapeInferenceContext* ctx,
                                      TF_ShapeHandle* handle) {
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  return cc_ctx->RankKnown(*reinterpret_cast<ShapeHandle*>(handle));
}

void TF_ShapeInferenceContextSetOutput(TF_ShapeInferenceContext* ctx, int i,
                                       TF_ShapeHandle* handle,
                                       TF_Status* status) {
  TF_SetStatus(status, TF_OK, "");
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  if (i < 0 || i >= cc_ctx->num_outputs()) {
    TF_SetStatus(status, TF_INVALID_ARGUMENT, "output index out of range");
  }
  if (TF_GetCode(status) == TF_OK) {
    cc_ctx->set_output(i, *(reinterpret_cast<ShapeHandle*>(handle)));
  }
}

void TF_DeleteShapeHandle(TF_ShapeHandle* handle) {
  if (handle == nullptr) {
    return;
  }

  delete reinterpret_cast<ShapeHandle*>(handle);
}

void TF_DeleteDimensionHandle(TF_DimensionHandle* handle) {
  if (handle == nullptr) {
    return;
  }

  delete reinterpret_cast<DimensionHandle*>(handle);
}

#define DEFINE_TF_GETATTR(func, c_type, cc_type)                         \
  void TF_ShapeInferenceContext_GetAttr##func(                           \
      TF_ShapeInferenceContext* ctx, const char* attr_name, c_type* val, \
      TF_Status* status) {                                               \
    TF_SetStatus(status, TF_OK, "");                                     \
    cc_type v;                                                           \
    auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);             \
    Status s = cc_ctx->GetAttr(attr_name, &v);                           \
    Set_TF_Status_from_Status(status, s);                                \
    if (s.ok()) {                                                        \
      *val = static_cast<c_type>(v);                                     \
    }                                                                    \
  }

DEFINE_TF_GETATTR(Type, TF_DataType, tensorflow::DataType)

#define DEFINE_RANK_FUNC(func_name)                                        \
  void TF_ShapeInferenceContext##func_name(                                \
      TF_ShapeInferenceContext* ctx, TF_ShapeHandle* handle, int64_t rank, \
      TF_ShapeHandle* result, TF_Status* status) {                         \
    auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);               \
    auto* cc_handle = reinterpret_cast<ShapeHandle*>(handle);              \
    auto* cc_result = reinterpret_cast<ShapeHandle*>(result);              \
    Status s = cc_ctx->func_name(*cc_handle, rank, cc_result);             \
    Set_TF_Status_from_Status(status, s);                                  \
  }

DEFINE_RANK_FUNC(WithRank)
DEFINE_RANK_FUNC(WithRankAtLeast)
DEFINE_RANK_FUNC(WithRankAtMost)

int64_t TF_ShapeInferenceContextRank(TF_ShapeInferenceContext* ctx,
                                     TF_ShapeHandle* handle) {
  return reinterpret_cast<InferenceContext*>(ctx)->Rank(
      *reinterpret_cast<ShapeHandle*>(handle));
}

void TF_ShapeInferenceContextDim(TF_ShapeInferenceContext* ctx,
                                 TF_ShapeHandle* shape_handle, int64_t i,
                                 TF_DimensionHandle* result) {
  int64_t rank = TF_ShapeInferenceContextRank(ctx, shape_handle);
  auto* cc_result = reinterpret_cast<DimensionHandle*>(result);

  if (i < -rank || i >= rank) {
    *cc_result = DimensionHandle();
    return;
  }

  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  auto* cc_shape_handle = reinterpret_cast<ShapeHandle*>(shape_handle);
  *cc_result = cc_ctx->Dim(*cc_shape_handle, i);
}

int TF_DimensionHandleValueKnown(TF_DimensionHandle* dim_handle) {
  return InferenceContext::ValueKnown(
      *reinterpret_cast<DimensionHandle*>(dim_handle));
}

void TF_ShapeInferenceContextSetUnknownShape(TF_ShapeInferenceContext* ctx,
                                             TF_Status* status) {
  Status s = ::tensorflow::shape_inference::UnknownShape(
      reinterpret_cast<InferenceContext*>(ctx));
  Set_TF_Status_from_Status(status, s);
}

void TF_ShapeInferenceContextSubshape(TF_ShapeInferenceContext* ctx,
                                      TF_ShapeHandle* shape_handle,
                                      int64_t start, int64_t end,
                                      TF_ShapeHandle* result,
                                      TF_Status* status) {
  TF_SetStatus(status, TF_OK, "");
  auto* cc_ctx = reinterpret_cast<InferenceContext*>(ctx);
  auto* cc_result = reinterpret_cast<ShapeHandle*>(result);
  Status s = cc_ctx->Subshape(*reinterpret_cast<ShapeHandle*>(shape_handle),
                              start, end, cc_result);
  Set_TF_Status_from_Status(status, s);
}

int64_t TF_DimensionHandleValue(TF_DimensionHandle* dim_handle) {
  return InferenceContext::Value(
      *reinterpret_cast<DimensionHandle*>(dim_handle));
}
<|endoftext|>


<commit_before>#include <catch.hpp>
#include <rapidcheck-catch.h>

#include "util/Util.h"
#include "util/Generators.h"
#include "util/TemplateProps.h"

#include "rapidcheck/detail/Configuration.h"
#include "rapidcheck/Check.h"

using namespace rc;
using namespace rc::detail;

template<>
class Arbitrary<TestParams> : public gen::Generator<TestParams>
{
public:
    TestParams generate() const override
    {
        TestParams params;
        params.maxSuccess = *gen::ranged(0, 100);
        params.maxSize = *gen::ranged(0, 101);
        params.maxDiscardRatio = *gen::ranged(0, 100);
        return params;
    }
};

// Generates a constant value but tries to shrink it by a sequence of
// decrementing towards zero. Used for testing the correct number of shrinks are
// performed/reported.
class CountDownGenerator : public gen::Generator<int>
{
public:
    CountDownGenerator(int value)
        : m_value(value) {}

    int generate() const override
    { return m_value; }

    shrink::IteratorUP<int> shrink(int value) const override
    {
        if (value == 0)
            return shrink::nothing<int>();

        return shrink::unfold(
            value,
            [](int x) { return x >= 0; },
            [](int x) { return std::make_pair(x - 1, x - 1); });
    }

private:
    const int m_value;
};

TEST_CASE("TestParams") {
    SECTION("operator==/operator!=") {
        propConformsToEquals<TestParams>();
        PROP_REPLACE_MEMBER_INEQUAL(TestParams, seed);
        PROP_REPLACE_MEMBER_INEQUAL(TestParams, maxSuccess);
        PROP_REPLACE_MEMBER_INEQUAL(TestParams, maxSize);
        PROP_REPLACE_MEMBER_INEQUAL(TestParams, maxDiscardRatio);
    }
}

TEST_CASE("checkTestable") {
    prop("runs all test cases if no cases fail",
         [] (const TestParams &params) {
             int numCases = 0;
             int lastSize = -1;
             auto result = checkTestable([&] {
                 numCases++;
             }, params);
             RC_ASSERT(numCases == params.maxSuccess);

             SuccessResult success;
             RC_ASSERT(result.match(success));
             RC_ASSERT(success.numSuccess == params.maxSuccess);
         });

    prop("returns correct information about failing case",
         [] (const TestParams &params) {
             RC_PRE(params.maxSuccess > 0);
             int caseIndex = 0;
             int lastSize = -1;
             // TODO test seed?
             int targetSuccess = *gen::ranged<int>(0, params.maxSuccess);
             auto result = checkTestable([&] {
                 lastSize = gen::currentSize();
                 RC_ASSERT(caseIndex < targetSuccess);
                 caseIndex++;
             }, params);
             FailureResult failure;
             RC_ASSERT(result.match(failure));
             RC_ASSERT(failure.numSuccess == targetSuccess);
             RC_ASSERT(failure.failingCase.size == lastSize);
         });

    prop("returns the correct number of shrinks on a failing case",
         [] {
             auto evenInteger = gen::scale(
                 0.25,
                 gen::suchThat(
                     gen::positive<int>(),
                     [](int x) { return (x % 2) == 0; }));
             auto values = *gen::pairOf(evenInteger, evenInteger);
             auto results = checkTestable([&] {
                 auto v1 = *CountDownGenerator(values.first);
                 auto v2 = *CountDownGenerator(values.second);
                 return ((v1 % 2) != 0) || ((v2 % 2) != 0);
             });

             FailureResult failure;
             RC_ASSERT(results.match(failure));
             RC_ASSERT(failure.numShrinks == ((values.first / 2) +
                                              (values.second / 2)));
         });

    prop("returns a correct counter-example",
         [] (std::vector<int> values) {
             auto results = checkTestable([&] {
                 for (auto value : values)
                     *gen::constant(value);
                 return false;
             });

             FailureResult failure;
             RC_ASSERT(results.match(failure));
             RC_ASSERT(failure.counterExample.size() == values.size());
             for (int i = 0; i < values.size(); i++) {
                 RC_ASSERT(failure.counterExample[i] ==
                           ValueDescription(values[i]));
             }
         });

    prop("counter-example is not affected by nested tests",
         [] {
             auto results = checkTestable([] {
                 *gen::constant<std::string>("foo");
                 auto innerResults = checkTestable([&] {
                     *gen::constant<std::string>("bar");
                     *gen::constant<std::string>("baz");
                 });

                 return false;
             });

             FailureResult failure;
             RC_ASSERT(results.match(failure));
             RC_ASSERT(failure.counterExample.size() == 1);
             RC_ASSERT(failure.counterExample[0] ==
                       ValueDescription(std::string("foo")));
         });

    prop("on failure, description contains message",
         [] (const std::string &description) {
             auto results = checkTestable([&] {
                 RC_FAIL(description);
             });

             FailureResult failure;
             RC_ASSERT(results.match(failure));
             RC_ASSERT(failure.description.find(description) !=
                       std::string::npos);
         });

    prop("gives up if too many test cases are discarded",
         [] (const TestParams &params) {
             RC_PRE(params.maxSuccess > 0);
             const int maxDiscards = params.maxSuccess * params.maxDiscardRatio;
             const int targetSuccess = *gen::ranged<int>(0, params.maxSuccess);
             int numTests = 0;
             auto results = checkTestable([&] {
                 numTests++;
                 RC_PRE(numTests <= targetSuccess);
             }, params);
             RC_ASSERT(numTests >= (targetSuccess + maxDiscards));

             GaveUpResult gaveUp;
             RC_ASSERT(results.match(gaveUp));
             RC_ASSERT(gaveUp.numSuccess == targetSuccess);
         });

    prop("does not give up if not enough tests are discarded",
         [] (const TestParams &params) {
             const int maxDiscards = params.maxSuccess * params.maxDiscardRatio;
             const int targetDiscard = *gen::ranged<int>(0, maxDiscards + 1);
             int numTests = 0;
             auto results = checkTestable([&] {
                 numTests++;
                 RC_PRE(numTests > targetDiscard);
             }, params);

             SuccessResult success;
             RC_ASSERT(results.match(success));
             RC_ASSERT(success.numSuccess == params.maxSuccess);
         });

    prop("on giving up, description contains message",
         [] (const std::string &description) {
             auto results = checkTestable([&] {
                 RC_DISCARD(description);
             });

             GaveUpResult gaveUp;
             RC_ASSERT(results.match(gaveUp));
             RC_ASSERT(gaveUp.description.find(description) !=
                       std::string::npos);
         });

    prop("running the same test with the same TestParams yields identical runs",
         [] (const TestParams &params) {
             std::vector<std::vector<int>> values;
             auto property = [&] {
                 auto x = *gen::arbitrary<std::vector<int>>();
                 values.push_back(x);
                 auto result = std::find(begin(x), end(x), 50);
                 return result == end(x);
             };

             auto results1 = checkTestable(property, params);
             auto values1 = std::move(values);

             values = std::vector<std::vector<int>>();
             auto results2 = checkTestable(property, params);
             auto values2 = std::move(values);

             RC_ASSERT(results1 == results2);
             RC_ASSERT(values1 == values2);
         });
}

TEST_CASE("defaultTestParams") {
    prop("takes default params from ImplicitParam<CurrentConfiguration>",
         [] (const Configuration &config) {
             TestParams expected;
             expected.seed = config.seed;
             expected.maxSuccess = config.defaultMaxSuccess;
             expected.maxSize = config.defaultMaxSize;
             expected.maxDiscardRatio = config.defaultMaxDiscardRatio;

             ImplicitParam<param::CurrentConfiguration> currentConfig(config);
             RC_ASSERT(defaultTestParams() == expected);
         });
}
<commit_msg>Remove outdated TODO comment<commit_after>#include <catch.hpp>
#include <rapidcheck-catch.h>

#include "util/Util.h"
#include "util/Generators.h"
#include "util/TemplateProps.h"

#include "rapidcheck/detail/Configuration.h"
#include "rapidcheck/Check.h"

using namespace rc;
using namespace rc::detail;

template<>
class Arbitrary<TestParams> : public gen::Generator<TestParams>
{
public:
    TestParams generate() const override
    {
        TestParams params;
        params.maxSuccess = *gen::ranged(0, 100);
        params.maxSize = *gen::ranged(0, 101);
        params.maxDiscardRatio = *gen::ranged(0, 100);
        return params;
    }
};

// Generates a constant value but tries to shrink it by a sequence of
// decrementing towards zero. Used for testing the correct number of shrinks are
// performed/reported.
class CountDownGenerator : public gen::Generator<int>
{
public:
    CountDownGenerator(int value)
        : m_value(value) {}

    int generate() const override
    { return m_value; }

    shrink::IteratorUP<int> shrink(int value) const override
    {
        if (value == 0)
            return shrink::nothing<int>();

        return shrink::unfold(
            value,
            [](int x) { return x >= 0; },
            [](int x) { return std::make_pair(x - 1, x - 1); });
    }

private:
    const int m_value;
};

TEST_CASE("TestParams") {
    SECTION("operator==/operator!=") {
        propConformsToEquals<TestParams>();
        PROP_REPLACE_MEMBER_INEQUAL(TestParams, seed);
        PROP_REPLACE_MEMBER_INEQUAL(TestParams, maxSuccess);
        PROP_REPLACE_MEMBER_INEQUAL(TestParams, maxSize);
        PROP_REPLACE_MEMBER_INEQUAL(TestParams, maxDiscardRatio);
    }
}

TEST_CASE("checkTestable") {
    prop("runs all test cases if no cases fail",
         [] (const TestParams &params) {
             int numCases = 0;
             int lastSize = -1;
             auto result = checkTestable([&] {
                 numCases++;
             }, params);
             RC_ASSERT(numCases == params.maxSuccess);

             SuccessResult success;
             RC_ASSERT(result.match(success));
             RC_ASSERT(success.numSuccess == params.maxSuccess);
         });

    prop("returns correct information about failing case",
         [] (const TestParams &params) {
             RC_PRE(params.maxSuccess > 0);
             int caseIndex = 0;
             int lastSize = -1;
             int targetSuccess = *gen::ranged<int>(0, params.maxSuccess);
             auto result = checkTestable([&] {
                 lastSize = gen::currentSize();
                 RC_ASSERT(caseIndex < targetSuccess);
                 caseIndex++;
             }, params);
             FailureResult failure;
             RC_ASSERT(result.match(failure));
             RC_ASSERT(failure.numSuccess == targetSuccess);
             RC_ASSERT(failure.failingCase.size == lastSize);
         });

    prop("returns the correct number of shrinks on a failing case",
         [] {
             auto evenInteger = gen::scale(
                 0.25,
                 gen::suchThat(
                     gen::positive<int>(),
                     [](int x) { return (x % 2) == 0; }));
             auto values = *gen::pairOf(evenInteger, evenInteger);
             auto results = checkTestable([&] {
                 auto v1 = *CountDownGenerator(values.first);
                 auto v2 = *CountDownGenerator(values.second);
                 return ((v1 % 2) != 0) || ((v2 % 2) != 0);
             });

             FailureResult failure;
             RC_ASSERT(results.match(failure));
             RC_ASSERT(failure.numShrinks == ((values.first / 2) +
                                              (values.second / 2)));
         });

    prop("returns a correct counter-example",
         [] (std::vector<int> values) {
             auto results = checkTestable([&] {
                 for (auto value : values)
                     *gen::constant(value);
                 return false;
             });

             FailureResult failure;
             RC_ASSERT(results.match(failure));
             RC_ASSERT(failure.counterExample.size() == values.size());
             for (int i = 0; i < values.size(); i++) {
                 RC_ASSERT(failure.counterExample[i] ==
                           ValueDescription(values[i]));
             }
         });

    prop("counter-example is not affected by nested tests",
         [] {
             auto results = checkTestable([] {
                 *gen::constant<std::string>("foo");
                 auto innerResults = checkTestable([&] {
                     *gen::constant<std::string>("bar");
                     *gen::constant<std::string>("baz");
                 });

                 return false;
             });

             FailureResult failure;
             RC_ASSERT(results.match(failure));
             RC_ASSERT(failure.counterExample.size() == 1);
             RC_ASSERT(failure.counterExample[0] ==
                       ValueDescription(std::string("foo")));
         });

    prop("on failure, description contains message",
         [] (const std::string &description) {
             auto results = checkTestable([&] {
                 RC_FAIL(description);
             });

             FailureResult failure;
             RC_ASSERT(results.match(failure));
             RC_ASSERT(failure.description.find(description) !=
                       std::string::npos);
         });

    prop("gives up if too many test cases are discarded",
         [] (const TestParams &params) {
             RC_PRE(params.maxSuccess > 0);
             const int maxDiscards = params.maxSuccess * params.maxDiscardRatio;
             const int targetSuccess = *gen::ranged<int>(0, params.maxSuccess);
             int numTests = 0;
             auto results = checkTestable([&] {
                 numTests++;
                 RC_PRE(numTests <= targetSuccess);
             }, params);
             RC_ASSERT(numTests >= (targetSuccess + maxDiscards));

             GaveUpResult gaveUp;
             RC_ASSERT(results.match(gaveUp));
             RC_ASSERT(gaveUp.numSuccess == targetSuccess);
         });

    prop("does not give up if not enough tests are discarded",
         [] (const TestParams &params) {
             const int maxDiscards = params.maxSuccess * params.maxDiscardRatio;
             const int targetDiscard = *gen::ranged<int>(0, maxDiscards + 1);
             int numTests = 0;
             auto results = checkTestable([&] {
                 numTests++;
                 RC_PRE(numTests > targetDiscard);
             }, params);

             SuccessResult success;
             RC_ASSERT(results.match(success));
             RC_ASSERT(success.numSuccess == params.maxSuccess);
         });

    prop("on giving up, description contains message",
         [] (const std::string &description) {
             auto results = checkTestable([&] {
                 RC_DISCARD(description);
             });

             GaveUpResult gaveUp;
             RC_ASSERT(results.match(gaveUp));
             RC_ASSERT(gaveUp.description.find(description) !=
                       std::string::npos);
         });

    prop("running the same test with the same TestParams yields identical runs",
         [] (const TestParams &params) {
             std::vector<std::vector<int>> values;
             auto property = [&] {
                 auto x = *gen::arbitrary<std::vector<int>>();
                 values.push_back(x);
                 auto result = std::find(begin(x), end(x), 50);
                 return result == end(x);
             };

             auto results1 = checkTestable(property, params);
             auto values1 = std::move(values);

             values = std::vector<std::vector<int>>();
             auto results2 = checkTestable(property, params);
             auto values2 = std::move(values);

             RC_ASSERT(results1 == results2);
             RC_ASSERT(values1 == values2);
         });
}

TEST_CASE("defaultTestParams") {
    prop("takes default params from ImplicitParam<CurrentConfiguration>",
         [] (const Configuration &config) {
             TestParams expected;
             expected.seed = config.seed;
             expected.maxSuccess = config.defaultMaxSuccess;
             expected.maxSize = config.defaultMaxSize;
             expected.maxDiscardRatio = config.defaultMaxDiscardRatio;

             ImplicitParam<param::CurrentConfiguration> currentConfig(config);
             RC_ASSERT(defaultTestParams() == expected);
         });
}
<|endoftext|>


<commit_before>#include "ShareStore.h"

class A: public BaseDllWrapper<A> {
	DEFINE_CDECL_FUNCTION(Func0, void())
	DEFINE_CDECL_FUNCTION(Func1, void(int))
	DEFINE_CDECL_FUNCTION(Func2, void(int, int))
	DEFINE_CDECL_FUNCTION(Func3, void(int, int, int))
	DEFINE_CDECL_FUNCTION(Func4, void(int, int, int, int))
	DEFINE_CDECL_FUNCTION(Func5, void(int, int, int, int, int))
	DEFINE_CDECL_FUNCTION(Func6, void(int, int, int, int, int, int))
	DEFINE_CDECL_FUNCTION(Func7, void(int, int, int, int, int, int, int))
	DEFINE_CDECL_FUNCTION(Func8, void(int, int, int, int, int, int, int, int))
	DEFINE_CDECL_FUNCTION(Func9, void(int, int, int, int, int, int, int, int, int))
};

#ifdef WIN32

#include "ShareStore.h"

class ShareUser32 : public BaseDllWrapper<ShareUser32> {
	DEFINE_STDCALL_FUNCTION(GetClientRect, BOOL(HWND, LPRECT));
	DEFINE_STDCALL_FUNCTION(GetDesktopWindow, HWND());

	// 动态存储使用懒加载模式
	DEFINE_DEFAULT_FILE("User32.dll");
};

#include "StaticStore.h"

class StaticUser32 : public BaseDllWrapper<StaticUser32> {
	DEFINE_STDCALL_FUNCTION(GetClientRect, BOOL(HWND, LPRECT));
	DEFINE_STDCALL_FUNCTION(GetDesktopWindow, HWND());

	// 静态存储使用懒加载模式
	DEFINE_DEFAULT_FILE("User32.dll");
};

#endif /* WIN32 */

#include "ShareStore.h"

class DllTest: public BaseDllWrapper<DllTest> {
	DEFINE_CDECL_FUNCTION(fnDllTest, int())
};

#ifdef WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif /* WIN32 */

int main(int argc, char* argv[]) {

	A().Func0();

	A().Func1();
	A().Func1(1);

	A().Func2();
	A().Func2(1);
	A().Func2(1, 2);

	A().Func3();
	A().Func3(1);
	A().Func3(1, 2);
	A().Func3(1, 2, 3);

	A().Func4();
	A().Func4(1);
	A().Func4(1, 2);
	A().Func4(1, 2, 3);
	A().Func4(1, 2, 3, 4);

	A().Func5();
	A().Func5(1);
	A().Func5(1, 2);
	A().Func5(1, 2, 3);
	A().Func5(1, 2, 3, 4);
	A().Func5(1, 2, 3, 4, 5);

	A().Func6();
	A().Func6(1);
	A().Func6(1, 2);
	A().Func6(1, 2, 3);
	A().Func6(1, 2, 3, 4);
	A().Func6(1, 2, 3, 4, 5);
	A().Func6(1, 2, 3, 4, 5, 6);

	A().Func7();
	A().Func7(1);
	A().Func7(1, 2);
	A().Func7(1, 2, 3);
	A().Func7(1, 2, 3, 4);
	A().Func7(1, 2, 3, 4, 5);
	A().Func7(1, 2, 3, 4, 5, 6);
	A().Func7(1, 2, 3, 4, 5, 6, 7);

	A().Func8();
	A().Func8(1, 2);
	A().Func8(1, 2, 3);
	A().Func8(1, 2, 3, 4);
	A().Func8(1, 2, 3, 4, 5);
	A().Func8(1, 2, 3, 4, 5, 6);
	A().Func8(1, 2, 3, 4, 5, 6, 7);
	A().Func8(1, 2, 3, 4, 5, 6, 7, 8);

	A().Func9();
	A().Func9(1);
	A().Func9(1, 2);
	A().Func9(1, 2, 3);
	A().Func9(1, 2, 3, 4);
	A().Func9(1, 2, 3, 4, 5);
	A().Func9(1, 2, 3, 4, 5, 6);
	A().Func9(1, 2, 3, 4, 5, 6, 7);
	A().Func9(1, 2, 3, 4, 5, 6, 7, 8);
	A().Func9(1, 2, 3, 4, 5, 6, 7, 8, 9);

	//////////////////////////////////////////////////////////////////////////

#ifdef WIN32

	RECT rcWnd;

	// 动态存储懒加载
	ShareUser32 mUser32;
	HWND hWnd = mUser32.GetDesktopWindow();
	mUser32.GetClientRect(hWnd, &rcWnd);
	mUser32.Free();

	// 静态存储懒加载
	hWnd = StaticUser32::GetDesktopWindow();
	StaticUser32::GetClientRect(hWnd, &rcWnd);
	StaticUser32::Free();

#endif

	//////////////////////////////////////////////////////////////////////////

	char buffer[256];
	getcwd(buffer, sizeof(buffer));

	//////////////////////////////////////////////////////////////////////////

	DllTest DllTestInst;

	// 动态存储切换加载资源
#ifdef WIN32
	DllTestInst.Load("DllTestOne.dll");
#else
	StdString OnePath(buffer);
#ifdef __APPLE__
	OnePath.append("/DllTestOne.dylib");
#else
    OnePath.append("/DllTestOne.so");
#endif
	DllTestInst.Load(OnePath.c_str());
#endif
	DllTestInst.fnDllTest();
	DllTestInst.Free();

	// 动态存储切换加载资源
#ifdef WIN32
	DllTestInst.Load("DllTestTwo.dll");
#else
	StdString TwoPath(buffer);
#ifdef __APPLE__
	TwoPath.append("/DllTestTwo.dylib");
#else
    TwoPath.append("/DllTestTwo.so");
#endif
	DllTestInst.Load(TwoPath.c_str());
#endif
	DllTestInst.fnDllTest();
	DllTestInst.Free();

	return 0;
}
<commit_msg>Update DynamicLib.cpp<commit_after>#include "ShareStore.h"

class A: public BaseDllWrapper<A> {
	DEFINE_CDECL_FUNCTION(Func0, void())
	DEFINE_CDECL_FUNCTION(Func1, void(int))
	DEFINE_CDECL_FUNCTION(Func2, void(int, int))
	DEFINE_CDECL_FUNCTION(Func3, void(int, int, int))
	DEFINE_CDECL_FUNCTION(Func4, void(int, int, int, int))
	DEFINE_CDECL_FUNCTION(Func5, void(int, int, int, int, int))
	DEFINE_CDECL_FUNCTION(Func6, void(int, int, int, int, int, int))
	DEFINE_CDECL_FUNCTION(Func7, void(int, int, int, int, int, int, int))
	DEFINE_CDECL_FUNCTION(Func8, void(int, int, int, int, int, int, int, int))
	DEFINE_CDECL_FUNCTION(Func9, void(int, int, int, int, int, int, int, int, int))
};

#ifdef WIN32

#include "ShareStore.h"

class ShareUser32 : public BaseDllWrapper<ShareUser32> {
	DEFINE_STDCALL_FUNCTION(GetClientRect, BOOL(HWND, LPRECT));
	DEFINE_STDCALL_FUNCTION(GetDesktopWindow, HWND());

	// 动态存储使用懒加载模式
	DEFINE_DEFAULT_FILE("User32.dll");
};

#include "StaticStore.h"

class StaticUser32 : public BaseDllWrapper<StaticUser32> {
	DEFINE_STDCALL_FUNCTION(GetClientRect, BOOL(HWND, LPRECT));
	DEFINE_STDCALL_FUNCTION(GetDesktopWindow, HWND());

	// 静态存储使用懒加载模式
	DEFINE_DEFAULT_FILE("User32.dll");
};

#endif /* WIN32 */

#include "ShareStore.h"

class DllTest: public BaseDllWrapper<DllTest> {
	DEFINE_CDECL_FUNCTION(fnDllTest, int())
};

#ifdef WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif /* WIN32 */

int main(int argc, char* argv[]) {

	A().Func0();

	A().Func1();
	A().Func1(1);

	A().Func2();
	A().Func2(1);
	A().Func2(1, 2);

	A().Func3();
	A().Func3(1);
	A().Func3(1, 2);
	A().Func3(1, 2, 3);

	A().Func4();
	A().Func4(1);
	A().Func4(1, 2);
	A().Func4(1, 2, 3);
	A().Func4(1, 2, 3, 4);

	A().Func5();
	A().Func5(1);
	A().Func5(1, 2);
	A().Func5(1, 2, 3);
	A().Func5(1, 2, 3, 4);
	A().Func5(1, 2, 3, 4, 5);

	A().Func6();
	A().Func6(1);
	A().Func6(1, 2);
	A().Func6(1, 2, 3);
	A().Func6(1, 2, 3, 4);
	A().Func6(1, 2, 3, 4, 5);
	A().Func6(1, 2, 3, 4, 5, 6);

	A().Func7();
	A().Func7(1);
	A().Func7(1, 2);
	A().Func7(1, 2, 3);
	A().Func7(1, 2, 3, 4);
	A().Func7(1, 2, 3, 4, 5);
	A().Func7(1, 2, 3, 4, 5, 6);
	A().Func7(1, 2, 3, 4, 5, 6, 7);

	A().Func8();
	A().Func8(1, 2);
	A().Func8(1, 2, 3);
	A().Func8(1, 2, 3, 4);
	A().Func8(1, 2, 3, 4, 5);
	A().Func8(1, 2, 3, 4, 5, 6);
	A().Func8(1, 2, 3, 4, 5, 6, 7);
	A().Func8(1, 2, 3, 4, 5, 6, 7, 8);

	A().Func9();
	A().Func9(1);
	A().Func9(1, 2);
	A().Func9(1, 2, 3);
	A().Func9(1, 2, 3, 4);
	A().Func9(1, 2, 3, 4, 5);
	A().Func9(1, 2, 3, 4, 5, 6);
	A().Func9(1, 2, 3, 4, 5, 6, 7);
	A().Func9(1, 2, 3, 4, 5, 6, 7, 8);
	A().Func9(1, 2, 3, 4, 5, 6, 7, 8, 9);

	//////////////////////////////////////////////////////////////////////////

#ifdef WIN32

	RECT rcWnd;

	// 动态存储懒加载
	ShareUser32 mUser32;
	HWND hWnd = mUser32.GetDesktopWindow();
	mUser32.GetClientRect(hWnd, &rcWnd);
	mUser32.Free();

	// 静态存储懒加载
	hWnd = StaticUser32::GetDesktopWindow();
	StaticUser32::GetClientRect(hWnd, &rcWnd);
	StaticUser32::Free();

#endif

	//////////////////////////////////////////////////////////////////////////

	char buffer[256];
	getcwd(buffer, sizeof(buffer));

	//////////////////////////////////////////////////////////////////////////

	DllTest DllTestInst;

	// 动态存储切换加载资源
#ifdef WIN32
	DllTestInst.Load("DllTestOne.dll");
#else
	StdString OnePath(buffer);
#ifdef __APPLE__
	OnePath.append("/DllTestOne.dylib");
#else
    	OnePath.append("/DllTestOne.so");
#endif
	DllTestInst.Load(OnePath.c_str());
#endif
	DllTestInst.fnDllTest();
	DllTestInst.Free();

	// 动态存储切换加载资源
#ifdef WIN32
	DllTestInst.Load("DllTestTwo.dll");
#else
	StdString TwoPath(buffer);
#ifdef __APPLE__
	TwoPath.append("/DllTestTwo.dylib");
#else
    	TwoPath.append("/DllTestTwo.so");
#endif
	DllTestInst.Load(TwoPath.c_str());
#endif
	DllTestInst.fnDllTest();
	DllTestInst.Free();

	return 0;
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <algorithm>
#include <limits>
#include <stdint.h>
#include <iostream>
#include <random>
#include <numeric>
#include <getopt.h>
#include <sstream>
#include <iomanip>
#include <functional>

#include "tblis.hpp"
#include "util/util.hpp"

using namespace std;
using namespace blis;
using namespace tblis;
using namespace tblis::impl;
using namespace tblis::util;
using namespace tblis::blis_like;

namespace tblis
{
namespace util
{
mt19937 engine;
}
}

template <dim_t Rsub=1>
double RunKernel(dim_t R, const function<void()>& kernel)
{
    double bias = numeric_limits<double>::max();
    for (dim_t r = 0;r < R;r++)
    {
        double t0 = bli_clock();
        double t1 = bli_clock();
        bias = min(bias, t1-t0);
    }

    double dt = numeric_limits<double>::max();
    for (dim_t r = 0;r < R;r++)
    {
        double t0 = bli_clock();
        for (dim_t rs = 0;rs < Rsub;rs++) kernel();
        double t1 = bli_clock();
        dt = min(dt, t1-t0);
    }

    return dt-bias;
}

void RunExperiment(dim_t m0, dim_t m1, dim_t m_step,
                   dim_t n0, dim_t n1, dim_t n_step,
                   dim_t k0, dim_t k1, dim_t k_step,
                   const function<void(dim_t,dim_t,dim_t)>& experiment)
{
    for (dim_t m = m0, n = n0, k = k0;
         m >= min(m0,m1) && m <= max(m0,m1) &&
         n >= min(n0,n1) && n <= max(n0,n1) &&
         k >= min(k0,k1) && k <= max(k0,k1);
         m += m_step, n += n_step, k += k_step)
    {
        experiment(m, n, k);
    }
}

template <typename T>
void Benchmark(gint_t R)
{
    using namespace std::placeholders;

    FILE *mout, *tout;

    auto experiment =
    [&](dim_t m, dim_t n, dim_t k, const std::function<double(double,dim_t,dim_t,dim_t)>& eff_dim)
    {
        printf("%ld %ld %ld\n", m, n, k);

        T alpha = 1.0;
        T beta = 0.0;

        {
            Matrix<T> A(m, k);
            Matrix<T> B(k, n);
            Matrix<T> C(m, n);
            A = 0.0;
            B = 0.0;
            C = 0.0;

            Scalar<T> alp(alpha);
            Scalar<T> bet(beta);

            double gflops = 2*m*n*k*1e-9;
            double dt_1 = RunKernel(R, [&]{ bli_gemm(alp, A, B, bet, C); });
            double dt_2 = RunKernel(R,
            [&]
            {
                Matrix<T> A2(k, m);
                Matrix<T> B2(k, n);
                Matrix<T> C2(m, n);
                A2.transpose();
                tblis_copyv(false, m*k, A.data(), 1, A2.data(), 1);
                tblis_copyv(false, k*n, B.data(), 1, B2.data(), 1);
                bli_gemm(alp, A2, B2, bet, C2);
                tblis_xpbyv(false, m*n, C2.data(), 1, beta, C.data(), 1);
            });
            fprintf(mout, "%e %e %e\n", eff_dim(gflops,m,n,k), gflops/dt_1, gflops/dt_2);
        }

        for (int i = 0;i < 3;i++)
        {
            vector<dim_t> len_m = RandomProductConstrainedSequence<dim_t, ROUND_NEAREST>(RandomInteger(1, 3), m);
            vector<dim_t> len_n = RandomProductConstrainedSequence<dim_t, ROUND_NEAREST>(RandomInteger(1, 3), n);
            vector<dim_t> len_k = RandomProductConstrainedSequence<dim_t, ROUND_NEAREST>(RandomInteger(1, 3), k);

            string idx_A, idx_B, idx_C;
            vector<dim_t> len_A, len_B, len_C;
            char idx = 'a';

            dim_t tm = 1;
            for (dim_t len : len_m)
            {
                idx_A.push_back(idx);
                len_A.push_back(len);
                idx_C.push_back(idx);
                len_C.push_back(len);
                idx++;
                tm *= len;
            }

            dim_t tn = 1;
            for (dim_t len : len_n)
            {
                idx_B.push_back(idx);
                len_B.push_back(len);
                idx_C.push_back(idx);
                len_C.push_back(len);
                idx++;
                tn *= len;
            }

            dim_t tk = 1;
            for (dim_t len : len_k)
            {
                idx_A.push_back(idx);
                len_A.push_back(len);
                idx_B.push_back(idx);
                len_B.push_back(len);
                idx++;
                tk *= len;
            }

            vector<int> reorder_A = range<int>(len_A.size());
            vector<int> reorder_B = range<int>(len_B.size());
            vector<int> reorder_C = range<int>(len_C.size());

            random_shuffle(reorder_A.begin(), reorder_A.end());
            random_shuffle(reorder_B.begin(), reorder_B.end());
            random_shuffle(reorder_C.begin(), reorder_C.end());

            idx_A = permute(idx_A, reorder_A);
            len_A = permute(len_A, reorder_A);
            idx_B = permute(idx_B, reorder_B);
            len_B = permute(len_B, reorder_B);
            idx_C = permute(idx_C, reorder_C);
            len_C = permute(len_C, reorder_C);

            Tensor<T> A(len_A.size(), len_A);
            Tensor<T> B(len_B.size(), len_B);
            Tensor<T> C(len_C.size(), len_C);

            len_A.resize(6);
            len_B.resize(6);
            len_C.resize(6);

            double gflops = 2*tm*tn*tk*1e-9;
            impl_type = BLAS_BASED;
            double dt_blas = RunKernel(R, [&]{ tensor_contract(alpha, A, idx_A, B, idx_B, beta, C, idx_C); });
            impl_type = BLIS_BASED;
            double dt_blis = RunKernel(R, [&]{ tensor_contract(alpha, A, idx_A, B, idx_B, beta, C, idx_C); });
            fprintf(tout, "%e %e %e - %s %ld %ld %ld %ld %ld %ld - %s %ld %ld %ld %ld %ld %ld - %s %ld %ld %ld %ld %ld %ld\n",
                    eff_dim(gflops,m,n,k), gflops/dt_blas, gflops/dt_blis,
                    idx_A.c_str(), len_A[0], len_A[1], len_A[2], len_A[3], len_A[4], len_A[5],
                    idx_B.c_str(), len_B[0], len_B[1], len_B[2], len_B[3], len_B[4], len_B[5],
                    idx_C.c_str(), len_C[0], len_C[1], len_C[2], len_C[3], len_C[4], len_C[5]);
        }
    };

    if (1)
    {
        mout = fopen("out.mat.square", "w");
        tout = fopen("out.tensor.square", "w");

        auto square_exp = bind(experiment, _1, _2, _3,
                               [](double gflops, dim_t m, dim_t n, dim_t k)
                               { return pow(gflops/2e-9, 1.0/3.0); });
        RunExperiment(10, 500, 10,
                      10, 500, 10,
                      10, 500, 10,
                      square_exp);

        fclose(mout);
        fclose(tout);
    }

    if (1)
    {
        mout = fopen("out.mat.rankk", "w");
        tout = fopen("out.tensor.rankk", "w");

        auto rankk_exp = bind(experiment, _1, _2, _3,
                              [](double gflops, dim_t m, dim_t n, dim_t k)
                              { return gflops/2e-9/m/n; });
        RunExperiment(500, 500, 0,
                      500, 500, 0,
                      10, 500, 10,
                      rankk_exp);

        fclose(mout);
        fclose(tout);
    }

    if (1)
    {
        mout = fopen("out.mat.pp", "w");
        tout = fopen("out.tensor.pp", "w");

        auto pp_exp = bind(experiment, _1, _2, _3,
                           [](double gflops, dim_t m, dim_t n, dim_t k)
                           { return sqrt(gflops/2e-9/k); });
        RunExperiment(10, 500, 10,
                      10, 500, 10,
                      256, 256, 0,
                      pp_exp);

        fclose(mout);
        fclose(tout);
    }

    if (1)
    {
        mout = fopen("out.mat.bp", "w");
        tout = fopen("out.tensor.bp", "w");

        auto bp_exp = bind(experiment, _1, _2, _3,
                           [](double gflops, dim_t m, dim_t n, dim_t k)
                           { return gflops/2e-9/m/k; });
        RunExperiment(96, 96, 0,
                      10, 1000, 10,
                      256, 256, 0,
                      bp_exp);

        fclose(mout);
        fclose(tout);
    }
}

int main(int argc, char **argv)
{
    gint_t R = 20;
    time_t seed = time(NULL);

    tblis_init();

    struct option opts[] = {{"rep", required_argument, NULL, 'r'},
                            {"seed", required_argument, NULL, 's'},
                            {0, 0, 0, 0}};

    int arg;
    int index;
    istringstream iss;
    while ((arg = getopt_long(argc, argv, "r:s:", opts, &index)) != -1)
    {
        switch (arg)
        {
            case 'r':
                iss.str(optarg);
                iss >> R;
                break;
            case 's':
                iss.str(optarg);
                iss >> seed;
                break;
            case '?':
                abort();
                break;
        }
    }

    cout << "Using mt19937 with seed " << seed << endl;
    engine.seed(seed);

    Benchmark<double>(R);

    tblis_finalize();

    return 0;
}
<commit_msg>Add non-random benchmark.<commit_after>#include <cstdlib>
#include <algorithm>
#include <limits>
#include <stdint.h>
#include <iostream>
#include <random>
#include <numeric>
#include <getopt.h>
#include <sstream>
#include <iomanip>
#include <functional>

#include "tblis.hpp"
#include "util/util.hpp"

using namespace std;
using namespace blis;
using namespace tblis;
using namespace tblis::impl;
using namespace tblis::util;
using namespace tblis::blis_like;

namespace tblis
{
namespace util
{
mt19937 engine;
}
}

template <dim_t Rsub=1>
double RunKernel(dim_t R, const function<void()>& kernel)
{
    double bias = numeric_limits<double>::max();
    for (dim_t r = 0;r < R;r++)
    {
        double t0 = bli_clock();
        double t1 = bli_clock();
        bias = min(bias, t1-t0);
    }

    double dt = numeric_limits<double>::max();
    for (dim_t r = 0;r < R;r++)
    {
        double t0 = bli_clock();
        for (dim_t rs = 0;rs < Rsub;rs++) kernel();
        double t1 = bli_clock();
        dt = min(dt, t1-t0);
    }

    return dt-bias;
}

void RunExperiment(dim_t m0, dim_t m1, dim_t m_step,
                   dim_t n0, dim_t n1, dim_t n_step,
                   dim_t k0, dim_t k1, dim_t k_step,
                   const function<void(dim_t,dim_t,dim_t)>& experiment)
{
    for (dim_t m = m0, n = n0, k = k0;
         m >= min(m0,m1) && m <= max(m0,m1) &&
         n >= min(n0,n1) && n <= max(n0,n1) &&
         k >= min(k0,k1) && k <= max(k0,k1);
         m += m_step, n += n_step, k += k_step)
    {
        experiment(m, n, k);
    }
}

template <typename T>
void Benchmark(gint_t R)
{
    using namespace std::placeholders;

    FILE *mout, *tout;

    auto reg_experiment =
    [&](dim_t m, dim_t n, dim_t k, const std::function<double(double,dim_t,dim_t,dim_t)>& eff_dim)
    {
        printf("%ld %ld %ld\n", m, n, k);

        T alpha = 1.0;
        T beta = 0.0;

        {
            Matrix<T> A(m, k);
            Matrix<T> B(k, n);
            Matrix<T> C(m, n);
            A = 0.0;
            B = 0.0;
            C = 0.0;

            Scalar<T> alp(alpha);
            Scalar<T> bet(beta);

            double gflops = 2*m*n*k*1e-9;
            double dt_1 = RunKernel(R, [&]{ bli_gemm(alp, A, B, bet, C); });
            double dt_2 = RunKernel(R,
            [&]
            {
                Matrix<T> A2(k, m);
                Matrix<T> B2(k, n);
                Matrix<T> C2(m, n);
                A2.transpose();
                tblis_copyv(false, m*k, A.data(), 1, A2.data(), 1);
                tblis_copyv(false, k*n, B.data(), 1, B2.data(), 1);
                bli_gemm(alp, A2, B2, bet, C2);
                tblis_xpbyv(false, m*n, C2.data(), 1, beta, C.data(), 1);
            });
            fprintf(mout, "%e %e %e\n", eff_dim(gflops,m,n,k), gflops/dt_1, gflops/dt_2);
        }

        {
            Tensor<T> A(4, vector<dim_t>{m/10, k/10, 10, 10});
            Tensor<T> B(4, vector<dim_t>{k/10, n/10, 10, 10});
            Tensor<T> C(4, vector<dim_t>{m/10, n/10, 10, 10});

            double gflops = 2*m*n*k*1e-9;
            impl_type = BLAS_BASED;
            double dt_blas = RunKernel(R, [&]{ tensor_contract(alpha, A, "aebf", B, "ecfd", beta, C, "acbd"); });
            impl_type = BLIS_BASED;
            double dt_blis = RunKernel(R, [&]{ tensor_contract(alpha, A, "aebf", B, "ecfd", beta, C, "acbd"); });
            fprintf(tout, "%e %e %e\n", eff_dim(gflops,m,n,k), gflops/dt_blas, gflops/dt_blis);
        }
    };

    if (1)
    {
        mout = fopen("out.mat.reg.square", "w");
        tout = fopen("out.tensor.reg.square", "w");

        auto square_exp = bind(reg_experiment, _1, _2, _3,
                               [](double gflops, dim_t m, dim_t n, dim_t k)
                               { return pow(gflops/2e-9, 1.0/3.0); });
        RunExperiment(20, 1000, 20,
                      20, 1000, 20,
                      20, 1000, 20,
                      square_exp);

        fclose(mout);
        fclose(tout);
    }

    if (1)
    {
        mout = fopen("out.mat.reg.rankk", "w");
        tout = fopen("out.tensor.reg.rankk", "w");

        auto rankk_exp = bind(reg_experiment, _1, _2, _3,
                              [](double gflops, dim_t m, dim_t n, dim_t k)
                              { return gflops/2e-9/m/n; });
        RunExperiment(1000, 1000,  0,
                      1000, 1000,  0,
                        20, 1000, 20,
                      rankk_exp);

        fclose(mout);
        fclose(tout);
    }

    if (1)
    {
        mout = fopen("out.mat.reg.pp", "w");
        tout = fopen("out.tensor.reg.pp", "w");

        auto pp_exp = bind(reg_experiment, _1, _2, _3,
                           [](double gflops, dim_t m, dim_t n, dim_t k)
                           { return sqrt(gflops/2e-9/k); });
        RunExperiment( 20, 1000, 20,
                       20, 1000, 20,
                      250,  250,  0,
                      pp_exp);

        fclose(mout);
        fclose(tout);
    }

    if (1)
    {
        mout = fopen("out.mat.reg.bp", "w");
        tout = fopen("out.tensor.reg.bp", "w");

        auto bp_exp = bind(reg_experiment, _1, _2, _3,
                           [](double gflops, dim_t m, dim_t n, dim_t k)
                           { return gflops/2e-9/m/k; });
        RunExperiment( 90,   90,  0,
                       20, 2000, 20,
                      250,  250,  0,
                      bp_exp);

        fclose(mout);
        fclose(tout);
    }

    auto rand_experiment =
    [&](dim_t m, dim_t n, dim_t k, const std::function<double(double,dim_t,dim_t,dim_t)>& eff_dim)
    {
        printf("%ld %ld %ld\n", m, n, k);

        T alpha = 1.0;
        T beta = 0.0;

        {
            Matrix<T> A(m, k);
            Matrix<T> B(k, n);
            Matrix<T> C(m, n);
            A = 0.0;
            B = 0.0;
            C = 0.0;

            Scalar<T> alp(alpha);
            Scalar<T> bet(beta);

            double gflops = 2*m*n*k*1e-9;
            double dt_1 = RunKernel(R, [&]{ bli_gemm(alp, A, B, bet, C); });
            double dt_2 = RunKernel(R,
            [&]
            {
                Matrix<T> A2(k, m);
                Matrix<T> B2(k, n);
                Matrix<T> C2(m, n);
                A2.transpose();
                tblis_copyv(false, m*k, A.data(), 1, A2.data(), 1);
                tblis_copyv(false, k*n, B.data(), 1, B2.data(), 1);
                bli_gemm(alp, A2, B2, bet, C2);
                tblis_xpbyv(false, m*n, C2.data(), 1, beta, C.data(), 1);
            });
            fprintf(mout, "%e %e %e\n", eff_dim(gflops,m,n,k), gflops/dt_1, gflops/dt_2);
        }

        for (int i = 0;i < 3;i++)
        {
            vector<dim_t> len_m = RandomProductConstrainedSequence<dim_t, ROUND_NEAREST>(RandomInteger(1, 3), m);
            vector<dim_t> len_n = RandomProductConstrainedSequence<dim_t, ROUND_NEAREST>(RandomInteger(1, 3), n);
            vector<dim_t> len_k = RandomProductConstrainedSequence<dim_t, ROUND_NEAREST>(RandomInteger(1, 3), k);

            string idx_A, idx_B, idx_C;
            vector<dim_t> len_A, len_B, len_C;
            char idx = 'a';

            dim_t tm = 1;
            for (dim_t len : len_m)
            {
                idx_A.push_back(idx);
                len_A.push_back(len);
                idx_C.push_back(idx);
                len_C.push_back(len);
                idx++;
                tm *= len;
            }

            dim_t tn = 1;
            for (dim_t len : len_n)
            {
                idx_B.push_back(idx);
                len_B.push_back(len);
                idx_C.push_back(idx);
                len_C.push_back(len);
                idx++;
                tn *= len;
            }

            dim_t tk = 1;
            for (dim_t len : len_k)
            {
                idx_A.push_back(idx);
                len_A.push_back(len);
                idx_B.push_back(idx);
                len_B.push_back(len);
                idx++;
                tk *= len;
            }

            vector<int> reorder_A = range<int>(len_A.size());
            vector<int> reorder_B = range<int>(len_B.size());
            vector<int> reorder_C = range<int>(len_C.size());

            random_shuffle(reorder_A.begin(), reorder_A.end());
            random_shuffle(reorder_B.begin(), reorder_B.end());
            random_shuffle(reorder_C.begin(), reorder_C.end());

            idx_A = permute(idx_A, reorder_A);
            len_A = permute(len_A, reorder_A);
            idx_B = permute(idx_B, reorder_B);
            len_B = permute(len_B, reorder_B);
            idx_C = permute(idx_C, reorder_C);
            len_C = permute(len_C, reorder_C);

            Tensor<T> A(len_A.size(), len_A);
            Tensor<T> B(len_B.size(), len_B);
            Tensor<T> C(len_C.size(), len_C);

            len_A.resize(6);
            len_B.resize(6);
            len_C.resize(6);

            double gflops = 2*tm*tn*tk*1e-9;
            impl_type = BLAS_BASED;
            double dt_blas = RunKernel(R, [&]{ tensor_contract(alpha, A, idx_A, B, idx_B, beta, C, idx_C); });
            impl_type = BLIS_BASED;
            double dt_blis = RunKernel(R, [&]{ tensor_contract(alpha, A, idx_A, B, idx_B, beta, C, idx_C); });
            fprintf(tout, "%e %e %e - %s %ld %ld %ld %ld %ld %ld - %s %ld %ld %ld %ld %ld %ld - %s %ld %ld %ld %ld %ld %ld\n",
                    eff_dim(gflops,m,n,k), gflops/dt_blas, gflops/dt_blis,
                    idx_A.c_str(), len_A[0], len_A[1], len_A[2], len_A[3], len_A[4], len_A[5],
                    idx_B.c_str(), len_B[0], len_B[1], len_B[2], len_B[3], len_B[4], len_B[5],
                    idx_C.c_str(), len_C[0], len_C[1], len_C[2], len_C[3], len_C[4], len_C[5]);
        }
    };

    if (1)
    {
        mout = fopen("out.mat.rand.square", "w");
        tout = fopen("out.tensor.rand.square", "w");

        auto square_exp = bind(rand_experiment, _1, _2, _3,
                               [](double gflops, dim_t m, dim_t n, dim_t k)
                               { return pow(gflops/2e-9, 1.0/3.0); });
        RunExperiment(20, 1000, 20,
                      20, 1000, 20,
                      20, 1000, 20,
                      square_exp);

        fclose(mout);
        fclose(tout);
    }

    if (1)
    {
        mout = fopen("out.mat.rand.rankk", "w");
        tout = fopen("out.tensor.rand.rankk", "w");

        auto rankk_exp = bind(rand_experiment, _1, _2, _3,
                              [](double gflops, dim_t m, dim_t n, dim_t k)
                              { return gflops/2e-9/m/n; });
        RunExperiment(1000, 1000,  0,
                      1000, 1000,  0,
                        20, 1000, 20,
                      rankk_exp);

        fclose(mout);
        fclose(tout);
    }

    if (1)
    {
        mout = fopen("out.mat.rand.pp", "w");
        tout = fopen("out.tensor.rand.pp", "w");

        auto pp_exp = bind(rand_experiment, _1, _2, _3,
                           [](double gflops, dim_t m, dim_t n, dim_t k)
                           { return sqrt(gflops/2e-9/k); });
        RunExperiment( 20, 1000, 20,
                       20, 1000, 20,
                      256,  256,  0,
                      pp_exp);

        fclose(mout);
        fclose(tout);
    }

    if (1)
    {
        mout = fopen("out.mat.rand.bp", "w");
        tout = fopen("out.tensor.rand.bp", "w");

        auto bp_exp = bind(rand_experiment, _1, _2, _3,
                           [](double gflops, dim_t m, dim_t n, dim_t k)
                           { return gflops/2e-9/m/k; });
        RunExperiment( 96,   96,  0,
                       20, 2000, 20,
                      256,  256,  0,
                      bp_exp);

        fclose(mout);
        fclose(tout);
    }
}

int main(int argc, char **argv)
{
    gint_t R = 20;
    time_t seed = time(NULL);

    tblis_init();

    struct option opts[] = {{"rep", required_argument, NULL, 'r'},
                            {"seed", required_argument, NULL, 's'},
                            {0, 0, 0, 0}};

    int arg;
    int index;
    istringstream iss;
    while ((arg = getopt_long(argc, argv, "r:s:", opts, &index)) != -1)
    {
        switch (arg)
        {
            case 'r':
                iss.str(optarg);
                iss >> R;
                break;
            case 's':
                iss.str(optarg);
                iss >> seed;
                break;
            case '?':
                abort();
                break;
        }
    }

    cout << "Using mt19937 with seed " << seed << endl;
    engine.seed(seed);

    Benchmark<double>(R);

    tblis_finalize();

    return 0;
}
<|endoftext|>