<commit_before>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "ArrayWranglerOperator.h"

#include "EditOperatorWidget.h"

#include <vtkFloatArray.h>
#include <vtkImageData.h>
#include <vtkNew.h>
#include <vtkPointData.h>
#include <vtkTypeUInt16Array.h>
#include <vtkTypeUInt8Array.h>

#include <QComboBox>
#include <QDebug>
#include <QHBoxLayout>
#include <QLabel>

namespace {

class ArrayWranglerWidget : public tomviz::EditOperatorWidget
{
  Q_OBJECT

public:
  ArrayWranglerWidget(tomviz::ArrayWranglerOperator* source,
                      vtkSmartPointer<vtkImageData> imageData, QWidget* p)
    : tomviz::EditOperatorWidget(p), m_operator(source),
      m_outputTypesCombo(nullptr), m_componentToKeepCombo(nullptr)
  {
    // Set up UI...
    auto* convertLabel = new QLabel("Convert to:", this);
    convertLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

    m_outputTypesCombo = new QComboBox(this);
    using OutputType = tomviz::ArrayWranglerOperator::OutputType;
    // This will ensure the combo box indexing matches that of the enum...
    m_outputTypesCombo->insertItem(static_cast<int>(OutputType::UInt8),
                                   "UInt8");
    m_outputTypesCombo->insertItem(static_cast<int>(OutputType::UInt16),
                                   "UInt16");

    auto* vBoxLayout = new QVBoxLayout(this);

    auto* convertHBoxLayout = new QHBoxLayout;
    convertHBoxLayout->addWidget(convertLabel);
    convertHBoxLayout->addWidget(m_outputTypesCombo);
    vBoxLayout->addLayout(convertHBoxLayout);

    auto numComponents =
      imageData->GetPointData()->GetScalars()->GetNumberOfComponents();
    if (numComponents > 1) {
      // Only add this option to the UI if there is more than one component
      auto* numComponentsLabel = new QLabel("Component to Keep:");
      numComponentsLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

      m_componentToKeepCombo = new QComboBox(this);
      // Populate combo box with component selection: 1, 2, 3...
      for (int i = 1; i < numComponents + 1; ++i)
        m_componentToKeepCombo->addItem(QString::number(i));

      auto* componentHBoxLayout = new QHBoxLayout;
      componentHBoxLayout->addWidget(numComponentsLabel);
      componentHBoxLayout->addWidget(m_componentToKeepCombo);
      vBoxLayout->addLayout(componentHBoxLayout);
    } else if (m_componentToKeepCombo) {
      // Ensure this is nullptr to communicate a component wasn't chosen
      m_componentToKeepCombo->deleteLater();
      m_componentToKeepCombo = nullptr;
    }

    setLayout(vBoxLayout);
  }

  void applyChangesToOperator() override
  {
    // The combo box and enum indices should match
    using OutputType = tomviz::ArrayWranglerOperator::OutputType;
    m_operator->setOutputType(
      static_cast<OutputType>(m_outputTypesCombo->currentIndex()));

    // Set the component we are to keep
    if (m_componentToKeepCombo)
      m_operator->setComponentToKeep(m_componentToKeepCombo->currentIndex());
    else
      m_operator->setComponentToKeep(0);
  }

private:
  QPointer<tomviz::ArrayWranglerOperator> m_operator;
  QComboBox* m_outputTypesCombo;
  QComboBox* m_componentToKeepCombo;
};
} // namespace

#include "ArrayWranglerOperator.moc"

namespace {

// This is specifically designed for unsigned integer output types
// The template is disabled for other output types
template <typename vtkInputDataType, typename vtkOutputArrayType,
          typename = std::enable_if<std::is_unsigned<
            decltype(vtkOutputArrayType::GetDataTypeValueMax())>::value>>
void wrangleVtkArrayTypeUnsigned(vtkOutputArrayType* array, int nComps,
                                 int componentToKeep, int nTuples, void* data,
                                 double oldrange[2])
{
  // We can't divide by zero...
  // assert(oldrange[1] != oldrange[0]);

  // GetDataTypeValueMax() is supposed to return the native data type
  auto newmax = vtkOutputArrayType::GetDataTypeValueMax();
  using outputType = decltype(newmax);

  // We will adjust the old range to the new range as follows:
  // new = ((old - oldmin) / oldrange * newrange) + newmin
  // For unsigned ints, newrange == newmax, and newmin == 0

  // Can be simplified to:
  // new = ((old - oldmin) * multiplier;
  // where multiplier is newmax / oldrange

  double multiplier = newmax / (oldrange[1] - oldrange[0]);

  auto d = static_cast<vtkInputDataType*>(data);
  auto a = static_cast<outputType*>(array->GetVoidPointer(0));
  for (vtkIdType i = 0; i < nTuples; ++i) {
    // Add 0.5 before casting to ensure flooring rounds correctly
    // We use a stride here to skip unwanted components in the source
    a[i] = static_cast<outputType>(
      (d[i * nComps + componentToKeep] - oldrange[0]) * multiplier + 0.5);
  }
}

template <typename vtkOutputArrayType>
void applyGenericWrangleTransform(vtkImageData* imageData, int componentToKeep)
{
  auto scalars = imageData->GetPointData()->GetScalars();

  // Get the range to input into the wrangle function
  double range[2];
  scalars->GetFiniteRange(range);

  vtkNew<vtkOutputArrayType> outputArray;
  outputArray->SetNumberOfComponents(1); // We will always use one component
  outputArray->SetNumberOfTuples(scalars->GetNumberOfTuples());
  outputArray->SetName(scalars->GetName());

  switch (scalars->GetDataType()) {
    vtkTemplateMacro(wrangleVtkArrayTypeUnsigned<VTK_TT>(
      outputArray.Get(), scalars->GetNumberOfComponents(), componentToKeep,
      scalars->GetNumberOfTuples(), scalars->GetVoidPointer(0), range));
  }

  imageData->GetPointData()->RemoveArray(scalars->GetName());
  imageData->GetPointData()->SetScalars(outputArray);
}
} // namespace

namespace tomviz {

ArrayWranglerOperator::ArrayWranglerOperator(QObject* p) : Operator(p)
{
}

QIcon ArrayWranglerOperator::icon() const
{
  return QIcon();
}

bool ArrayWranglerOperator::applyTransform(vtkDataObject* data)
{
  auto imageData = vtkImageData::SafeDownCast(data);
  // sanity check
  if (!imageData) {
    qDebug() << "Error in" << __FUNCTION__ << ": imageData is nullptr!";
    return false;
  }

  auto scalars = imageData->GetPointData()->GetScalars();
  // One more sanity check
  if (m_componentToKeep >= scalars->GetNumberOfComponents()) {
    qDebug() << "Error in" << __FUNCTION__ << ": componentToKeep,"
             << QString::number(m_componentToKeep) << "is greater than or "
             << "equal to the number of components:"
             << QString::number(scalars->GetNumberOfComponents());
    return false;
  }

  // Use a template to make it easier to add other types...
  switch (m_outputType) {
    case OutputType::UInt8:
      applyGenericWrangleTransform<vtkTypeUInt8Array>(imageData,
                                                      m_componentToKeep);
      break;
    case OutputType::UInt16:
      applyGenericWrangleTransform<vtkTypeUInt16Array>(imageData,
                                                       m_componentToKeep);
      break;
    default:
      qDebug() << "Error in" << __FUNCTION__ << ": unknown output type!";
      return false;
  }

  return true;
}

QJsonObject ArrayWranglerOperator::serialize() const
{
  auto json = Operator::serialize();
  QJsonValue outputType(static_cast<int>(m_outputType));
  QJsonValue componentToKeep(m_componentToKeep);
  json["outputType"] = outputType;
  json["componentToKeep"] = componentToKeep;
  return json;
}

bool ArrayWranglerOperator::deserialize(const QJsonObject& json)
{
  if (json.contains("outputType"))
    m_outputType = static_cast<OutputType>(json["outputType"].toInt());

  if (json.contains("componentToKeep"))
    m_componentToKeep = json["componentToKeep"].toInt();

  return true;
}

Operator* ArrayWranglerOperator::clone() const
{
  auto* other = new ArrayWranglerOperator();
  other->setOutputType(m_outputType);
  other->setComponentToKeep(m_componentToKeep);
  return other;
}

EditOperatorWidget* ArrayWranglerOperator::getEditorContentsWithData(
  QWidget* p, vtkSmartPointer<vtkImageData> data)
{
  return new ArrayWranglerWidget(this, data, p);
}

} // namespace tomviz
<commit_msg>Shorten name of internal transform function<commit_after>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "ArrayWranglerOperator.h"

#include "EditOperatorWidget.h"

#include <vtkFloatArray.h>
#include <vtkImageData.h>
#include <vtkNew.h>
#include <vtkPointData.h>
#include <vtkTypeUInt16Array.h>
#include <vtkTypeUInt8Array.h>

#include <QComboBox>
#include <QDebug>
#include <QHBoxLayout>
#include <QLabel>

namespace {

class ArrayWranglerWidget : public tomviz::EditOperatorWidget
{
  Q_OBJECT

public:
  ArrayWranglerWidget(tomviz::ArrayWranglerOperator* source,
                      vtkSmartPointer<vtkImageData> imageData, QWidget* p)
    : tomviz::EditOperatorWidget(p), m_operator(source),
      m_outputTypesCombo(nullptr), m_componentToKeepCombo(nullptr)
  {
    // Set up UI...
    auto* convertLabel = new QLabel("Convert to:", this);
    convertLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

    m_outputTypesCombo = new QComboBox(this);
    using OutputType = tomviz::ArrayWranglerOperator::OutputType;
    // This will ensure the combo box indexing matches that of the enum...
    m_outputTypesCombo->insertItem(static_cast<int>(OutputType::UInt8),
                                   "UInt8");
    m_outputTypesCombo->insertItem(static_cast<int>(OutputType::UInt16),
                                   "UInt16");

    auto* vBoxLayout = new QVBoxLayout(this);

    auto* convertHBoxLayout = new QHBoxLayout;
    convertHBoxLayout->addWidget(convertLabel);
    convertHBoxLayout->addWidget(m_outputTypesCombo);
    vBoxLayout->addLayout(convertHBoxLayout);

    auto numComponents =
      imageData->GetPointData()->GetScalars()->GetNumberOfComponents();
    if (numComponents > 1) {
      // Only add this option to the UI if there is more than one component
      auto* numComponentsLabel = new QLabel("Component to Keep:");
      numComponentsLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

      m_componentToKeepCombo = new QComboBox(this);
      // Populate combo box with component selection: 1, 2, 3...
      for (int i = 1; i < numComponents + 1; ++i)
        m_componentToKeepCombo->addItem(QString::number(i));

      auto* componentHBoxLayout = new QHBoxLayout;
      componentHBoxLayout->addWidget(numComponentsLabel);
      componentHBoxLayout->addWidget(m_componentToKeepCombo);
      vBoxLayout->addLayout(componentHBoxLayout);
    } else if (m_componentToKeepCombo) {
      // Ensure this is nullptr to communicate a component wasn't chosen
      m_componentToKeepCombo->deleteLater();
      m_componentToKeepCombo = nullptr;
    }

    setLayout(vBoxLayout);
  }

  void applyChangesToOperator() override
  {
    // The combo box and enum indices should match
    using OutputType = tomviz::ArrayWranglerOperator::OutputType;
    m_operator->setOutputType(
      static_cast<OutputType>(m_outputTypesCombo->currentIndex()));

    // Set the component we are to keep
    if (m_componentToKeepCombo)
      m_operator->setComponentToKeep(m_componentToKeepCombo->currentIndex());
    else
      m_operator->setComponentToKeep(0);
  }

private:
  QPointer<tomviz::ArrayWranglerOperator> m_operator;
  QComboBox* m_outputTypesCombo;
  QComboBox* m_componentToKeepCombo;
};
} // namespace

#include "ArrayWranglerOperator.moc"

namespace {

// This is specifically designed for unsigned integer output types
// The template is disabled for other output types
template <typename vtkInputDataType, typename vtkOutputArrayType,
          typename = std::enable_if<std::is_unsigned<
            decltype(vtkOutputArrayType::GetDataTypeValueMax())>::value>>
void wrangleVtkArrayTypeUnsigned(vtkOutputArrayType* array, int nComps,
                                 int componentToKeep, int nTuples, void* data,
                                 double oldrange[2])
{
  // We can't divide by zero...
  // assert(oldrange[1] != oldrange[0]);

  // GetDataTypeValueMax() is supposed to return the native data type
  auto newmax = vtkOutputArrayType::GetDataTypeValueMax();
  using outputType = decltype(newmax);

  // We will adjust the old range to the new range as follows:
  // new = ((old - oldmin) / oldrange * newrange) + newmin
  // For unsigned ints, newrange == newmax, and newmin == 0

  // Can be simplified to:
  // new = ((old - oldmin) * multiplier;
  // where multiplier is newmax / oldrange

  double multiplier = newmax / (oldrange[1] - oldrange[0]);

  auto d = static_cast<vtkInputDataType*>(data);
  auto a = static_cast<outputType*>(array->GetVoidPointer(0));
  for (vtkIdType i = 0; i < nTuples; ++i) {
    // Add 0.5 before casting to ensure flooring rounds correctly
    // We use a stride here to skip unwanted components in the source
    a[i] = static_cast<outputType>(
      (d[i * nComps + componentToKeep] - oldrange[0]) * multiplier + 0.5);
  }
}

template <typename vtkOutputArrayType>
void applyGenericTransform(vtkImageData* imageData, int componentToKeep)
{
  auto scalars = imageData->GetPointData()->GetScalars();

  // Get the range to input into the wrangle function
  double range[2];
  scalars->GetFiniteRange(range);

  vtkNew<vtkOutputArrayType> outputArray;
  outputArray->SetNumberOfComponents(1); // We will always use one component
  outputArray->SetNumberOfTuples(scalars->GetNumberOfTuples());
  outputArray->SetName(scalars->GetName());

  switch (scalars->GetDataType()) {
    vtkTemplateMacro(wrangleVtkArrayTypeUnsigned<VTK_TT>(
      outputArray.Get(), scalars->GetNumberOfComponents(), componentToKeep,
      scalars->GetNumberOfTuples(), scalars->GetVoidPointer(0), range));
  }

  imageData->GetPointData()->RemoveArray(scalars->GetName());
  imageData->GetPointData()->SetScalars(outputArray);
}
} // namespace

namespace tomviz {

ArrayWranglerOperator::ArrayWranglerOperator(QObject* p) : Operator(p)
{
}

QIcon ArrayWranglerOperator::icon() const
{
  return QIcon();
}

bool ArrayWranglerOperator::applyTransform(vtkDataObject* data)
{
  auto imageData = vtkImageData::SafeDownCast(data);
  // sanity check
  if (!imageData) {
    qDebug() << "Error in" << __FUNCTION__ << ": imageData is nullptr!";
    return false;
  }

  auto scalars = imageData->GetPointData()->GetScalars();
  // One more sanity check
  if (m_componentToKeep >= scalars->GetNumberOfComponents()) {
    qDebug() << "Error in" << __FUNCTION__ << ": componentToKeep,"
             << QString::number(m_componentToKeep) << "is greater than or "
             << "equal to the number of components:"
             << QString::number(scalars->GetNumberOfComponents());
    return false;
  }

  // Use a template to make it easier to add other types...
  switch (m_outputType) {
    case OutputType::UInt8:
      applyGenericTransform<vtkTypeUInt8Array>(imageData, m_componentToKeep);
      break;
    case OutputType::UInt16:
      applyGenericTransform<vtkTypeUInt16Array>(imageData, m_componentToKeep);
      break;
    default:
      qDebug() << "Error in" << __FUNCTION__ << ": unknown output type!";
      return false;
  }

  return true;
}

QJsonObject ArrayWranglerOperator::serialize() const
{
  auto json = Operator::serialize();
  QJsonValue outputType(static_cast<int>(m_outputType));
  QJsonValue componentToKeep(m_componentToKeep);
  json["outputType"] = outputType;
  json["componentToKeep"] = componentToKeep;
  return json;
}

bool ArrayWranglerOperator::deserialize(const QJsonObject& json)
{
  if (json.contains("outputType"))
    m_outputType = static_cast<OutputType>(json["outputType"].toInt());

  if (json.contains("componentToKeep"))
    m_componentToKeep = json["componentToKeep"].toInt();

  return true;
}

Operator* ArrayWranglerOperator::clone() const
{
  auto* other = new ArrayWranglerOperator();
  other->setOutputType(m_outputType);
  other->setComponentToKeep(m_componentToKeep);
  return other;
}

EditOperatorWidget* ArrayWranglerOperator::getEditorContentsWithData(
  QWidget* p, vtkSmartPointer<vtkImageData> data)
{
  return new ArrayWranglerWidget(this, data, p);
}

} // namespace tomviz
<|endoftext|>


<commit_before>#include "RST.hpp"
#include "countint.hpp"
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>

using namespace std;

/**
 * A simple benchmarking program for RST.
 */
static void show_usage()
{
  std::cerr << "./benchtree [rst, bst, set] [sorted, shuffled]"
               " [maximum tree size] [number of runs]" << endl;
}

int main (int argc, char** argv)
{
  if(argc != 5)
  {
    show_usage();
    return 1;
  }

  // parse arg 1: type of structure
  if(strcmp(argv[1], "bst") == 0)
  {
    BST<countint> * tree = new BST<countint>();
  }
  else if (strcmp(argv[1], "rst") == 0)
  {
    RST<countint> * tree = new RST<countint>();
  }
  else if (strcmp(argv[1], "set") == 0)
  {
    std::set<countint> * tree = new std::set<countint>();
  }
  else
  {
    show_usage();
    return 1;
  }

  //parse arg 2: keys in sorted or randomized order
  if(strcmp(argv[2], "sorted") == 0)
  {

  }
  else if(strcmp(argv[2], "shuffled") == 0)
  {

  }
  else
  {
    show_usage();
    return 1;
  }

  //parse arg 3: maximum size of tree
  if(isdigit(argv[3]))
  {
    int n = atoi (argv[3]);
  }
  else
  {
    show_usage();
    return 1;
  }

  //parse arg 4: number of runs
  if (isdigit(argv[4]))
  {
    int r = atoi( argv[4] );
  }
  else
  {
    show_usage();
    return 1;
  }
}
<commit_msg>slow and steady<commit_after>#include "RST.hpp"
#include "countint.hpp"
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>

using namespace std;

/**
 * A simple benchmarking program for RST.
 */
static void show_usage()
{
  std::cerr << "./benchtree [rst, bst, set] [sorted, shuffled]"
               " [maximum tree size] [number of runs]" << endl;
}

int main (int argc, char** argv)
{
  if(argc != 5)
  {
    show_usage();
    return 1;
  }

  // parse arg 1: type of structure
  if(strcmp(argv[1], "bst") == 0)
  {
    BST<countint> * bam = new BST<countint>();
  }
  else if (strcmp(argv[1], "rst") == 0)
  {
    RST<countint> * bam = new RST<countint>();
  }
  else if (strcmp(argv[1], "set") == 0)
  {
    std::set<countint> * bam = new std::set<countint>();
  }
  else
  {
    show_usage();
    return 1;
  }

  //parse arg 2: keys in sorted or randomized order
  if(strcmp(argv[2], "sorted") == 0)
  {
    std::vector<countint> v;
    v.clear();
  }
  else if(strcmp(argv[2], "shuffled") == 0)
  {

  }
  else
  {
    show_usage();
    return 1;
  }

  //parse arg 3: maximum size of tree
  if(isdigit(argv[3]))
  {
    int n = atoi (argv[3]);
  }
  else
  {
    show_usage();
    return 1;
  }

  //parse arg 4: number of runs
  if (isdigit(argv[4]))
  {
    int r = atoi( argv[4] );
  }
  else
  {
    show_usage();
    return 1;
  }
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_RANK_HPP
#define STAN_MATH_PRIM_FUN_RANK_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>

namespace stan {
namespace math {

/**
 * Return the number of components of v less than v[s].
 *
 * @tparam C container type
 * @param[in] v input vector
 * @param[in] s position in vector
 * @return number of components of v less than v[s].
 * @throw std::out_of_range if s is out of range.
 */
template <typename C, require_container_t<C>* = nullptr>
inline int rank(const C& v, int s) {
  check_range("rank", "v", v.size(), s);
  --s;  // adjust for indexing by one
  return apply_vector_unary<C>::reduce(v, [s](const auto& vec) {
    return (vec.array() < vec.coeff(s)).template cast<int>().sum();
  });
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>Made rank work with expressions<commit_after>#ifndef STAN_MATH_PRIM_FUN_RANK_HPP
#define STAN_MATH_PRIM_FUN_RANK_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>

namespace stan {
namespace math {

/**
 * Return the number of components of v less than v[s].
 *
 * @tparam C container type
 * @param[in] v input vector
 * @param[in] s position in vector
 * @return number of components of v less than v[s].
 * @throw std::out_of_range if s is out of range.
 */
template <typename C, require_container_t<C>* = nullptr>
inline int rank(const C& v, int s) {
  check_range("rank", "v", v.size(), s);
  --s;  // adjust for indexing by one
  return apply_vector_unary<C>::reduce(v, [s](const auto& vec) {
      const auto& vec_ref = to_ref(vec);

      return (vec_ref.array() < vec_ref.coeff(s)).template cast<int>().sum();
  });
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>/**
 * \file
 * \brief MutexPriorityInheritanceOperationsTestCase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-12
 */

#include "MutexPriorityInheritanceOperationsTestCase.hpp"

#include "distortos/Mutex.hpp"
#include "distortos/ThisThread.hpp"
#include "distortos/StaticThread.hpp"

#include "distortos/estd/ReferenceHolder.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// functor class used in testBasicPriorityInheritance() - it locks 0-3 mutexes and unlocks them afterwards
class BasicPriorityInheritanceThread
{
public:

	/**
	 * \brief BasicPriorityInheritanceThread's constructor
	 *
	 * \param [in] mutex1 is a pointer to first mutex
	 * \param [in] mutex2 is a pointer to second mutex
	 * \param [in] mutex3 is a pointer to third mutex
	 */

	constexpr BasicPriorityInheritanceThread(Mutex* const mutex1, Mutex* const mutex2, Mutex* const mutex3) :
			mutexes_{mutex1, mutex2, mutex3},
			ret_{}
	{

	}

	/**
	 * \return combined return value of Mutex::lock() / Mutex::unlock()
	 */

	int getRet() const
	{
		return ret_;
	}

	/**
	 * \brief Main function of the thread.
	 *
	 * Locks all provided mutexes and then unlocks them in the same order.
	 */

	void operator()()
	{
		for (const auto mutex : mutexes_)
			if (mutex != nullptr)
			{
				const auto ret = mutex->lock();
				if (ret != 0)
					ret_ = ret;
			}

		for (const auto mutex : mutexes_)
			if (mutex != nullptr)
			{
				const auto ret = mutex->unlock();
				if (ret != 0)
					ret_ = ret;
			}
	}

private:

	/// array with pointers to mutexes
	std::array<Mutex*, 3> mutexes_;

	/// combined return value of Mutex::lock() / Mutex::unlock()
	int ret_;
};

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {256};

/// priority of current test thread
constexpr uint8_t testThreadPriority {1};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Tests basic priority inheritance mechanism of mutexes with PriorityInheritance protocol.
 *
 * 10 threads are created and "connected" into a tree-like hierarchy using mutexes. This structure is presented on the
 * diagram below. Mutexes are marked with "Mx" boxes and threads with "Tx" ellipses. The higher the thread is drawn, the
 * higher its priority is (drawn on the side).
 *
 * \dot
 * digraph G
 * {
 * 		{
 * 			node [shape=plaintext];
 * 			"+10" -> "+9" -> "+8" -> "+7" -> "+6" -> "+5" -> "+4" -> "+3" -> "+2" -> "+1" -> "+0";
 * 		}
 *
 * 		{rank = same; "+10"; "T111";}
 * 		{rank = same; "+9"; "T110";}
 * 		{rank = same; "+8"; "T101";}
 * 		{rank = same; "+7"; "T100";}
 * 		{rank = same; "+6"; "T11";}
 * 		{rank = same; "+5"; "T10";}
 * 		{rank = same; "+4"; "T01";}
 * 		{rank = same; "+3"; "T00";}
 * 		{rank = same; "+2"; "T1";}
 * 		{rank = same; "+1"; "T0";}
 * 		{rank = same; "+0"; "main";}
 *
 * 		{
 * 			node [shape=box];
 * 			"M0"; "M1"; "M00"; "M01"; "M10"; "M11"; "M100"; "M101"; "M110"; "M111";
 * 		}
 *
 * 		"T111" -> "M111" -> "T11" -> "M11" -> "T1" -> "M1" -> "main";
 * 		"T110" -> "M110" -> "T11";
 * 		"T101" -> "M101" -> "T10" -> "M10" -> "T1";
 * 		"T100" -> "M100" -> "T10";
 * 		"T01" -> "M01" -> "T0" -> "M0" -> "main";
 * 		"T00" -> "M00" -> "T0";
 * }
 * \enddot
 *
 * Main thread is expected to inherit priority of each started test thread when this thread blocks on the mutex. After
 * the last step main thread will inherit priority of thread T111 through a chain of 3 mutexes blocking 3 threads. After
 * the test (when all links are broken) all priorities are expected to return to their previous values.
 *
 * \param [in] type is the Mutex::Type that will be tested
 *
 * \return true if the test case succeeded, false otherwise
 */

bool testBasicPriorityInheritance(const Mutex::Type type)
{
	constexpr size_t totalThreads {10};

	// effective priority (relative to testThreadPriority) for each test thread in each test step
	static const std::array<std::array<uint8_t, totalThreads>, totalThreads> priorityBoosts
	{{
			{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
			{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
			{3, 2, 3, 4, 5, 6, 7, 8, 9, 10},
			{4, 2, 3, 4, 5, 6, 7, 8, 9, 10},
			{4, 5, 3, 4, 5, 6, 7, 8, 9, 10},
			{4, 6, 3, 4, 5, 6, 7, 8, 9, 10},
			{4, 7, 3, 4, 7, 6, 7, 8, 9, 10},
			{4, 8, 3, 4, 8, 6, 7, 8, 9, 10},
			{4, 9, 3, 4, 8, 9, 7, 8, 9, 10},
			{4, 10, 3, 4, 8, 10, 7, 8, 9, 10},
	}};

	Mutex mutex0 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex1 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex00 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex01 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex10 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex11 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex100 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex101 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex110 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex111 {type, Mutex::Protocol::PriorityInheritance};

	BasicPriorityInheritanceThread threadObject0 {&mutex00, &mutex01, &mutex0};
	BasicPriorityInheritanceThread threadObject1 {&mutex10, &mutex11, &mutex1};
	BasicPriorityInheritanceThread threadObject00 {&mutex00, nullptr, nullptr};
	BasicPriorityInheritanceThread threadObject01 {&mutex01, nullptr, nullptr};
	BasicPriorityInheritanceThread threadObject10 {&mutex100, &mutex101, &mutex10};
	BasicPriorityInheritanceThread threadObject11 {&mutex110, &mutex111, &mutex11};
	BasicPriorityInheritanceThread threadObject100 {&mutex100, nullptr, nullptr};
	BasicPriorityInheritanceThread threadObject101 {&mutex101, nullptr, nullptr};
	BasicPriorityInheritanceThread threadObject110 {&mutex110, nullptr, nullptr};
	BasicPriorityInheritanceThread threadObject111 {&mutex111, nullptr, nullptr};

	auto thread0 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][0], std::ref(threadObject0));
	auto thread1 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][1], std::ref(threadObject1));
	auto thread00 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][2], std::ref(threadObject00));
	auto thread01 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][3], std::ref(threadObject01));
	auto thread10 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][4], std::ref(threadObject10));
	auto thread11 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][5], std::ref(threadObject11));
	auto thread100 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][6], std::ref(threadObject100));
	auto thread101 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][7], std::ref(threadObject101));
	auto thread110 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][8], std::ref(threadObject110));
	auto thread111 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][9], std::ref(threadObject111));

	std::array<estd::ReferenceHolder<decltype(thread0)>, totalThreads> threads
	{{
			thread0, thread1, thread00, thread01, thread10, thread11, thread100, thread101, thread110, thread111,
	}};

	bool result {true};

	{
		const auto ret = mutex0.lock();
		if (ret != 0)
			result = false;
	}
	{
		const auto ret = mutex1.lock();
		if (ret != 0)
			result = false;
	}

	for (size_t i = 0; i < threads.size(); ++i)
	{
		auto& thread = threads[i].get();
		thread.start();
		if (ThisThread::getEffectivePriority() != thread.getEffectivePriority())
			result = false;

		for (size_t j = 0; j < threads.size(); ++j)
			if (threads[j].get().getEffectivePriority() != testThreadPriority + priorityBoosts[i][j])
				result = false;
	}

	{
		const auto ret = mutex1.unlock();
		if (ret != 0)
			result = false;
	}

	if (ThisThread::getEffectivePriority() != thread0.getEffectivePriority())
		result = false;

	{
		const auto ret = mutex0.unlock();
		if (ret != 0)
			result = false;
	}

	for (const auto& thread : threads)
		thread.get().join();

	if (ThisThread::getEffectivePriority() != testThreadPriority)
		result = false;

	for (size_t i = 0; i < threads.size(); ++i)
		if (threads[i].get().getEffectivePriority() != testThreadPriority + priorityBoosts[0][i])
			result = false;

	for (const auto& threadObject : {threadObject0, threadObject1, threadObject00, threadObject01, threadObject10,
			threadObject11, threadObject100, threadObject101, threadObject110, threadObject111})
		if (threadObject.getRet() != 0)
			result = false;

	return result;
}

/**
 * \brief Runs the test case.
 *
 * \attention this function expects the priority of test thread to be testThreadPriority
 *
 * \return true if the test case succeeded, false otherwise
 */

bool testRunner()
{
	static const Mutex::Type types[]
	{
			Mutex::Type::Normal,
			Mutex::Type::ErrorChecking,
			Mutex::Type::Recursive,
	};

	for (const auto type : types)
	{
		{
			const auto result = testBasicPriorityInheritance(type);
			if (result != true)
				return result;
		}
	}

	return true;
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool MutexPriorityInheritanceOperationsTestCase::run_() const
{
	const auto thisThreadPriority = ThisThread::getPriority();
	ThisThread::setPriority(testThreadPriority);
	const auto ret = testRunner();
	ThisThread::setPriority(thisThreadPriority);
	return ret;
}

}	// namespace test

}	// namespace distortos
<commit_msg>test: make size of stack of test thread a local constant of testBasicPriorityInheritance() in MutexPriorityInheritanceOperationsTestCase<commit_after>/**
 * \file
 * \brief MutexPriorityInheritanceOperationsTestCase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-15
 */

#include "MutexPriorityInheritanceOperationsTestCase.hpp"

#include "distortos/Mutex.hpp"
#include "distortos/ThisThread.hpp"
#include "distortos/StaticThread.hpp"

#include "distortos/estd/ReferenceHolder.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// functor class used in testBasicPriorityInheritance() - it locks 0-3 mutexes and unlocks them afterwards
class BasicPriorityInheritanceThread
{
public:

	/**
	 * \brief BasicPriorityInheritanceThread's constructor
	 *
	 * \param [in] mutex1 is a pointer to first mutex
	 * \param [in] mutex2 is a pointer to second mutex
	 * \param [in] mutex3 is a pointer to third mutex
	 */

	constexpr BasicPriorityInheritanceThread(Mutex* const mutex1, Mutex* const mutex2, Mutex* const mutex3) :
			mutexes_{mutex1, mutex2, mutex3},
			ret_{}
	{

	}

	/**
	 * \return combined return value of Mutex::lock() / Mutex::unlock()
	 */

	int getRet() const
	{
		return ret_;
	}

	/**
	 * \brief Main function of the thread.
	 *
	 * Locks all provided mutexes and then unlocks them in the same order.
	 */

	void operator()()
	{
		for (const auto mutex : mutexes_)
			if (mutex != nullptr)
			{
				const auto ret = mutex->lock();
				if (ret != 0)
					ret_ = ret;
			}

		for (const auto mutex : mutexes_)
			if (mutex != nullptr)
			{
				const auto ret = mutex->unlock();
				if (ret != 0)
					ret_ = ret;
			}
	}

private:

	/// array with pointers to mutexes
	std::array<Mutex*, 3> mutexes_;

	/// combined return value of Mutex::lock() / Mutex::unlock()
	int ret_;
};

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// priority of current test thread
constexpr uint8_t testThreadPriority {1};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Tests basic priority inheritance mechanism of mutexes with PriorityInheritance protocol.
 *
 * 10 threads are created and "connected" into a tree-like hierarchy using mutexes. This structure is presented on the
 * diagram below. Mutexes are marked with "Mx" boxes and threads with "Tx" ellipses. The higher the thread is drawn, the
 * higher its priority is (drawn on the side).
 *
 * \dot
 * digraph G
 * {
 * 		{
 * 			node [shape=plaintext];
 * 			"+10" -> "+9" -> "+8" -> "+7" -> "+6" -> "+5" -> "+4" -> "+3" -> "+2" -> "+1" -> "+0";
 * 		}
 *
 * 		{rank = same; "+10"; "T111";}
 * 		{rank = same; "+9"; "T110";}
 * 		{rank = same; "+8"; "T101";}
 * 		{rank = same; "+7"; "T100";}
 * 		{rank = same; "+6"; "T11";}
 * 		{rank = same; "+5"; "T10";}
 * 		{rank = same; "+4"; "T01";}
 * 		{rank = same; "+3"; "T00";}
 * 		{rank = same; "+2"; "T1";}
 * 		{rank = same; "+1"; "T0";}
 * 		{rank = same; "+0"; "main";}
 *
 * 		{
 * 			node [shape=box];
 * 			"M0"; "M1"; "M00"; "M01"; "M10"; "M11"; "M100"; "M101"; "M110"; "M111";
 * 		}
 *
 * 		"T111" -> "M111" -> "T11" -> "M11" -> "T1" -> "M1" -> "main";
 * 		"T110" -> "M110" -> "T11";
 * 		"T101" -> "M101" -> "T10" -> "M10" -> "T1";
 * 		"T100" -> "M100" -> "T10";
 * 		"T01" -> "M01" -> "T0" -> "M0" -> "main";
 * 		"T00" -> "M00" -> "T0";
 * }
 * \enddot
 *
 * Main thread is expected to inherit priority of each started test thread when this thread blocks on the mutex. After
 * the last step main thread will inherit priority of thread T111 through a chain of 3 mutexes blocking 3 threads. After
 * the test (when all links are broken) all priorities are expected to return to their previous values.
 *
 * \param [in] type is the Mutex::Type that will be tested
 *
 * \return true if the test case succeeded, false otherwise
 */

bool testBasicPriorityInheritance(const Mutex::Type type)
{
	constexpr size_t testThreadStackSize {256};
	constexpr size_t totalThreads {10};

	// effective priority (relative to testThreadPriority) for each test thread in each test step
	static const std::array<std::array<uint8_t, totalThreads>, totalThreads> priorityBoosts
	{{
			{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
			{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
			{3, 2, 3, 4, 5, 6, 7, 8, 9, 10},
			{4, 2, 3, 4, 5, 6, 7, 8, 9, 10},
			{4, 5, 3, 4, 5, 6, 7, 8, 9, 10},
			{4, 6, 3, 4, 5, 6, 7, 8, 9, 10},
			{4, 7, 3, 4, 7, 6, 7, 8, 9, 10},
			{4, 8, 3, 4, 8, 6, 7, 8, 9, 10},
			{4, 9, 3, 4, 8, 9, 7, 8, 9, 10},
			{4, 10, 3, 4, 8, 10, 7, 8, 9, 10},
	}};

	Mutex mutex0 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex1 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex00 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex01 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex10 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex11 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex100 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex101 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex110 {type, Mutex::Protocol::PriorityInheritance};
	Mutex mutex111 {type, Mutex::Protocol::PriorityInheritance};

	BasicPriorityInheritanceThread threadObject0 {&mutex00, &mutex01, &mutex0};
	BasicPriorityInheritanceThread threadObject1 {&mutex10, &mutex11, &mutex1};
	BasicPriorityInheritanceThread threadObject00 {&mutex00, nullptr, nullptr};
	BasicPriorityInheritanceThread threadObject01 {&mutex01, nullptr, nullptr};
	BasicPriorityInheritanceThread threadObject10 {&mutex100, &mutex101, &mutex10};
	BasicPriorityInheritanceThread threadObject11 {&mutex110, &mutex111, &mutex11};
	BasicPriorityInheritanceThread threadObject100 {&mutex100, nullptr, nullptr};
	BasicPriorityInheritanceThread threadObject101 {&mutex101, nullptr, nullptr};
	BasicPriorityInheritanceThread threadObject110 {&mutex110, nullptr, nullptr};
	BasicPriorityInheritanceThread threadObject111 {&mutex111, nullptr, nullptr};

	auto thread0 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][0], std::ref(threadObject0));
	auto thread1 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][1], std::ref(threadObject1));
	auto thread00 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][2], std::ref(threadObject00));
	auto thread01 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][3], std::ref(threadObject01));
	auto thread10 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][4], std::ref(threadObject10));
	auto thread11 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][5], std::ref(threadObject11));
	auto thread100 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][6], std::ref(threadObject100));
	auto thread101 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][7], std::ref(threadObject101));
	auto thread110 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][8], std::ref(threadObject110));
	auto thread111 =
			makeStaticThread<testThreadStackSize>(testThreadPriority + priorityBoosts[0][9], std::ref(threadObject111));

	std::array<estd::ReferenceHolder<decltype(thread0)>, totalThreads> threads
	{{
			thread0, thread1, thread00, thread01, thread10, thread11, thread100, thread101, thread110, thread111,
	}};

	bool result {true};

	{
		const auto ret = mutex0.lock();
		if (ret != 0)
			result = false;
	}
	{
		const auto ret = mutex1.lock();
		if (ret != 0)
			result = false;
	}

	for (size_t i = 0; i < threads.size(); ++i)
	{
		auto& thread = threads[i].get();
		thread.start();
		if (ThisThread::getEffectivePriority() != thread.getEffectivePriority())
			result = false;

		for (size_t j = 0; j < threads.size(); ++j)
			if (threads[j].get().getEffectivePriority() != testThreadPriority + priorityBoosts[i][j])
				result = false;
	}

	{
		const auto ret = mutex1.unlock();
		if (ret != 0)
			result = false;
	}

	if (ThisThread::getEffectivePriority() != thread0.getEffectivePriority())
		result = false;

	{
		const auto ret = mutex0.unlock();
		if (ret != 0)
			result = false;
	}

	for (const auto& thread : threads)
		thread.get().join();

	if (ThisThread::getEffectivePriority() != testThreadPriority)
		result = false;

	for (size_t i = 0; i < threads.size(); ++i)
		if (threads[i].get().getEffectivePriority() != testThreadPriority + priorityBoosts[0][i])
			result = false;

	for (const auto& threadObject : {threadObject0, threadObject1, threadObject00, threadObject01, threadObject10,
			threadObject11, threadObject100, threadObject101, threadObject110, threadObject111})
		if (threadObject.getRet() != 0)
			result = false;

	return result;
}

/**
 * \brief Runs the test case.
 *
 * \attention this function expects the priority of test thread to be testThreadPriority
 *
 * \return true if the test case succeeded, false otherwise
 */

bool testRunner()
{
	static const Mutex::Type types[]
	{
			Mutex::Type::Normal,
			Mutex::Type::ErrorChecking,
			Mutex::Type::Recursive,
	};

	for (const auto type : types)
	{
		{
			const auto result = testBasicPriorityInheritance(type);
			if (result != true)
				return result;
		}
	}

	return true;
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool MutexPriorityInheritanceOperationsTestCase::run_() const
{
	const auto thisThreadPriority = ThisThread::getPriority();
	ThisThread::setPriority(testThreadPriority);
	const auto ret = testRunner();
	ThisThread::setPriority(thisThreadPriority);
	return ret;
}

}	// namespace test

}	// namespace distortos
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//      https://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.

// Main entry function for iree-opt and derived binaries.
//
// Based on mlir-opt but without registering passes and dialects we don't care
// about.

#include "iree/compiler/Conversion/HLOToLinalg/Passes.h"
#include "iree/compiler/Conversion/init_conversions.h"
#include "iree/compiler/Dialect/HAL/Conversion/Passes.h"
#include "iree/tools/init_compiler_modules.h"
#include "iree/tools/init_dialects.h"
#include "iree/tools/init_passes.h"
#include "iree/tools/init_targets.h"
#include "iree/tools/init_xla_dialects.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/ToolOutputFile.h"
#include "mlir/IR/AsmState.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Support/FileUtilities.h"
#include "mlir/Support/MlirOptMain.h"

static llvm::cl::opt<std::string> inputFilename(llvm::cl::Positional,
                                                llvm::cl::desc("<input file>"),
                                                llvm::cl::init("-"));

static llvm::cl::opt<std::string> outputFilename(
    "o", llvm::cl::desc("Output filename"), llvm::cl::value_desc("filename"),
    llvm::cl::init("-"));

static llvm::cl::opt<bool> splitInputFile(
    "split-input-file",
    llvm::cl::desc("Split the input file into pieces and process each "
                   "chunk independently"),
    llvm::cl::init(false));

static llvm::cl::opt<bool> verifyDiagnostics(
    "verify-diagnostics",
    llvm::cl::desc("Check that emitted diagnostics match "
                   "expected-* lines on the corresponding line"),
    llvm::cl::init(false));

static llvm::cl::opt<bool> verifyPasses(
    "verify-each",
    llvm::cl::desc("Run the verifier after each transformation pass"),
    llvm::cl::init(true));

static llvm::cl::opt<bool> allowUnregisteredDialects(
    "allow-unregistered-dialect",
    llvm::cl::desc("Allow operation with no registered dialects"),
    llvm::cl::init(true));

int main(int argc, char **argv) {
  mlir::registerMlirDialects();
  mlir::registerMlirPasses();
  mlir::registerXLADialects();
  mlir::iree_compiler::registerIreeDialects();
  mlir::iree_compiler::registerIreeCompilerModuleDialects();
  mlir::iree_compiler::registerAllIreePasses();
  mlir::iree_compiler::registerHALConversionPasses();
  mlir::iree_compiler::registerHALTargetBackends();
  mlir::iree_compiler::registerLinalgToSPIRVPasses();
  mlir::iree_compiler::registerHLOToLinalgPasses();
  llvm::InitLLVM y(argc, argv);

  // Register MLIRContext command-line options like
  // -mlir-print-op-on-diagnostic.
  mlir::registerMLIRContextCLOptions();
  // Register assembly printer command-line options like
  // -mlir-print-op-generic.
  mlir::registerAsmPrinterCLOptions();
  // Register pass manager command-line options like -print-ir-*.
  mlir::registerPassManagerCLOptions();

  mlir::PassPipelineCLParser passPipeline("", "Compiler passes to run");

  // Parse pass names in main to ensure static initialization completed.
  llvm::cl::ParseCommandLineOptions(argc, argv,
                                    "IREE modular optimizer driver\n");

  // Set up the input file.
  std::string errorMessage;
  auto file = mlir::openInputFile(inputFilename, &errorMessage);
  if (!file) {
    llvm::errs() << errorMessage << "\n";
    return 1;
  }

  auto output = mlir::openOutputFile(outputFilename, &errorMessage);
  if (!output) {
    llvm::errs() << errorMessage << "\n";
    exit(1);
  }

  return failed(mlir::MlirOptMain(output->os(), std::move(file), passPipeline,
                                  splitInputFile, verifyDiagnostics,
                                  verifyPasses, allowUnregisteredDialects));
}
<commit_msg>Add an option to iree-opt to show all registered dialect<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//      https://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.

// Main entry function for iree-opt and derived binaries.
//
// Based on mlir-opt but without registering passes and dialects we don't care
// about.

#include "iree/compiler/Conversion/HLOToLinalg/Passes.h"
#include "iree/compiler/Conversion/init_conversions.h"
#include "iree/compiler/Dialect/HAL/Conversion/Passes.h"
#include "iree/tools/init_compiler_modules.h"
#include "iree/tools/init_dialects.h"
#include "iree/tools/init_passes.h"
#include "iree/tools/init_targets.h"
#include "iree/tools/init_xla_dialects.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/ToolOutputFile.h"
#include "mlir/IR/AsmState.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Support/FileUtilities.h"
#include "mlir/Support/MlirOptMain.h"

static llvm::cl::opt<std::string> inputFilename(llvm::cl::Positional,
                                                llvm::cl::desc("<input file>"),
                                                llvm::cl::init("-"));

static llvm::cl::opt<std::string> outputFilename(
    "o", llvm::cl::desc("Output filename"), llvm::cl::value_desc("filename"),
    llvm::cl::init("-"));

static llvm::cl::opt<bool> splitInputFile(
    "split-input-file",
    llvm::cl::desc("Split the input file into pieces and process each "
                   "chunk independently"),
    llvm::cl::init(false));

static llvm::cl::opt<bool> verifyDiagnostics(
    "verify-diagnostics",
    llvm::cl::desc("Check that emitted diagnostics match "
                   "expected-* lines on the corresponding line"),
    llvm::cl::init(false));

static llvm::cl::opt<bool> verifyPasses(
    "verify-each",
    llvm::cl::desc("Run the verifier after each transformation pass"),
    llvm::cl::init(true));

static llvm::cl::opt<bool> allowUnregisteredDialects(
    "allow-unregistered-dialect",
    llvm::cl::desc("Allow operation with no registered dialects"),
    llvm::cl::init(true));

static llvm::cl::opt<bool> showDialects(
    "show-dialects", llvm::cl::desc("Print the list of registered dialects"),
    llvm::cl::init(false));

int main(int argc, char **argv) {
  mlir::registerMlirDialects();
  mlir::registerMlirPasses();
  mlir::registerXLADialects();
  mlir::iree_compiler::registerIreeDialects();
  mlir::iree_compiler::registerIreeCompilerModuleDialects();
  mlir::iree_compiler::registerAllIreePasses();
  mlir::iree_compiler::registerHALConversionPasses();
  mlir::iree_compiler::registerHALTargetBackends();
  mlir::iree_compiler::registerLinalgToSPIRVPasses();
  mlir::iree_compiler::registerHLOToLinalgPasses();
  llvm::InitLLVM y(argc, argv);

  // Register MLIRContext command-line options like
  // -mlir-print-op-on-diagnostic.
  mlir::registerMLIRContextCLOptions();
  // Register assembly printer command-line options like
  // -mlir-print-op-generic.
  mlir::registerAsmPrinterCLOptions();
  // Register pass manager command-line options like -print-ir-*.
  mlir::registerPassManagerCLOptions();

  mlir::PassPipelineCLParser passPipeline("", "Compiler passes to run");

  // Parse pass names in main to ensure static initialization completed.
  llvm::cl::ParseCommandLineOptions(argc, argv,
                                    "IREE modular optimizer driver\n");

  if (showDialects) {
    llvm::outs() << "Registered Dialects:\n";
    mlir::MLIRContext context;
    for (mlir::Dialect *dialect : context.getRegisteredDialects()) {
      llvm::outs() << dialect->getNamespace() << "\n";
    }
    return 0;
  }

  // Set up the input file.
  std::string errorMessage;
  auto file = mlir::openInputFile(inputFilename, &errorMessage);
  if (!file) {
    llvm::errs() << errorMessage << "\n";
    return 1;
  }

  auto output = mlir::openOutputFile(outputFilename, &errorMessage);
  if (!output) {
    llvm::errs() << errorMessage << "\n";
    exit(1);
  }

  return failed(mlir::MlirOptMain(output->os(), std::move(file), passPipeline,
                                  splitInputFile, verifyDiagnostics,
                                  verifyPasses, allowUnregisteredDialects));
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qgraphicsanchorlayout_p.h"

QGraphicsAnchorLayout::QGraphicsAnchorLayout(QGraphicsLayoutItem *parent)
    : QGraphicsLayout(*new QGraphicsAnchorLayoutPrivate(), parent)
{
    Q_D(QGraphicsAnchorLayout);
    d->createLayoutEdges();
}

QGraphicsAnchorLayout::~QGraphicsAnchorLayout()
{
    Q_D(QGraphicsAnchorLayout);

    for (int i = count() - 1; i >= 0; --i) {
        QGraphicsLayoutItem *item = d->items.at(i);
        removeAt(i);
        if (item) {
            if (item->ownedByLayout())
                delete item;
        }
    }

    d->removeCenterConstraints(this, QGraphicsAnchorLayoutPrivate::Horizontal);
    d->removeCenterConstraints(this, QGraphicsAnchorLayoutPrivate::Vertical);
    d->deleteLayoutEdges();

    Q_ASSERT(d->itemCenterConstraints[0].isEmpty());
    Q_ASSERT(d->itemCenterConstraints[1].isEmpty());
    Q_ASSERT(d->items.isEmpty());
    Q_ASSERT(d->m_vertexList.isEmpty());
}

/*!
 * Creates an anchor between the edge \a firstEdge of item \a firstItem and the edge \a secondEdge
 * of item \a secondItem. The magnitude of the anchor is picked up from the style. Anchors
 * between  a layout edge and an item edge will have a size of 0.
 * If there is already an anchor between the edges, the the new anchor will replace the old one.
 *
 * \a firstItem and \a secondItem are automatically added to the layout if they are not part
 * of the layout. This means that count() can increase with up to 2.
 *
 * The spacing an anchor will get depends on the type of anchor. For instance, anchors from the
 * Right edge of one item to the Left edge of another (or vice versa) will use the default
 * horizontal spacing. The same behaviour applies to Bottom to Top anchors, (but they will use
 * the default vertical spacing). For all other anchor combinations, the spacing will be 0.
 * All anchoring functions will follow this rule.
 *
 * \sa removeAnchor, anchorCorner, anchorWidth, anchorHeight, anchorGeometry
 */
void QGraphicsAnchorLayout::anchor(QGraphicsLayoutItem *firstItem,
                                   Edge firstEdge,
                                   QGraphicsLayoutItem *secondItem,
                                   Edge secondEdge)
{
    Q_D(QGraphicsAnchorLayout);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge);
    invalidate();
}

/*!
 * \overload
 *
 * By calling this function the caller can specify the magnitude of the anchor with \a spacing.
 *
 */
void QGraphicsAnchorLayout::anchor(QGraphicsLayoutItem *firstItem,
                                   Edge firstEdge,
                                   QGraphicsLayoutItem *secondItem,
                                   Edge secondEdge, qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge, &spacing);
    invalidate();
}

/*!
 * Creates two anchors between \a firstItem and \a secondItem, where one is for the horizontal
 * edge and another one for the vertical edge that the corners \a firstCorner and \a
 * secondCorner specifies.
 * The magnitude of the anchors is picked up from the style.
 *
 * This is a convenience function, since anchoring corners can be expressed as anchoring two edges.
 * For instance,
 * \code
 *  layout->anchor(layout, QGraphicsAnchorLayout::Top, b, QGraphicsAnchorLayout::Top);
 *  layout->anchor(layout, QGraphicsAnchorLayout::Left, b, QGraphicsAnchorLayout::Left);
 * \endcode
 *
 * has the same effect as
 *
 * \code
 * layout->anchor(layout, Qt::TopLeft, b, Qt::TopLeft);
 * \endcode
 *
 * If there is already an anchor between the edge pairs, it will be replaced by the anchors that
 * this function specifies.
 *
 * \a firstItem and \a secondItem are automatically added to the layout if they are not part
 * of the layout. This means that count() can increase with up to 2.
 */
void QGraphicsAnchorLayout::anchorCorner(QGraphicsLayoutItem *firstItem,
                                         Qt::Corner firstCorner,
                                         QGraphicsLayoutItem *secondItem,
                                         Qt::Corner secondCorner)
{
    Q_D(QGraphicsAnchorLayout);

    // Horizontal anchor
    QGraphicsAnchorLayout::Edge firstEdge = (firstCorner & 1 ? QGraphicsAnchorLayout::Right: QGraphicsAnchorLayout::Left);
    QGraphicsAnchorLayout::Edge secondEdge = (secondCorner & 1 ? QGraphicsAnchorLayout::Right: QGraphicsAnchorLayout::Left);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge);

    // Vertical anchor
    firstEdge = (firstCorner & 2 ? QGraphicsAnchorLayout::Bottom: QGraphicsAnchorLayout::Top);
    secondEdge = (secondCorner & 2 ? QGraphicsAnchorLayout::Bottom: QGraphicsAnchorLayout::Top);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge);

    invalidate();
}

/*!
 * \overload
 *
 * By calling this function the caller can specify the magnitude of the anchor with \a spacing.
 *
 */
void QGraphicsAnchorLayout::anchorCorner(QGraphicsLayoutItem *firstItem,
                                         Qt::Corner firstCorner,
                                         QGraphicsLayoutItem *secondItem,
                                         Qt::Corner secondCorner, qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);

    // Horizontal anchor
    QGraphicsAnchorLayout::Edge firstEdge = (firstCorner & 1 ? QGraphicsAnchorLayout::Right: QGraphicsAnchorLayout::Left);
    QGraphicsAnchorLayout::Edge secondEdge = (secondCorner & 1 ? QGraphicsAnchorLayout::Right: QGraphicsAnchorLayout::Left);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge, &spacing);

    // Vertical anchor
    firstEdge = (firstCorner & 2 ? QGraphicsAnchorLayout::Bottom: QGraphicsAnchorLayout::Top);
    secondEdge = (secondCorner & 2 ? QGraphicsAnchorLayout::Bottom: QGraphicsAnchorLayout::Top);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge, &spacing);

    invalidate();
}

void QGraphicsAnchorLayout::removeAnchor(QGraphicsLayoutItem *firstItem, Edge firstEdge,
                                         QGraphicsLayoutItem *secondItem, Edge secondEdge)
{
    Q_D(QGraphicsAnchorLayout);
    if ((firstItem == 0) || (secondItem == 0)) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor between NULL items");
        return;
    }

    if (firstItem == secondItem) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor from the item to itself");
        return;
    }

    if (d->edgeOrientation(secondEdge) != d->edgeOrientation(firstEdge)) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor from edges of different orientations");
        return;
    }

    d->removeAnchor(firstItem, firstEdge, secondItem, secondEdge);
    invalidate();
}

/*!
    Sets the default horizontal spacing for the anchor layout to \a spacing.

    \sa horizontalSpacing, setVerticalSpacing, setSpacing
*/
void QGraphicsAnchorLayout::setHorizontalSpacing(qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);
    d->spacings[0] = spacing;
    invalidate();
}

/*!
    Sets the default vertical spacing for the anchor layout to \a spacing.

    \sa verticalSpacing, setHorizontalSpacing, setSpacing
*/
void QGraphicsAnchorLayout::setVerticalSpacing(qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);
    d->spacings[1] = spacing;
    invalidate();
}

/*!
    Sets the default horizontal and the default vertical spacing for the anchor layout to \a spacing.

    If an item is anchored with no spacing associated with the anchor, it will use the default
    spacing.
    \sa setHorizontalSpacing, setVerticalSpacing
*/
void QGraphicsAnchorLayout::setSpacing(qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);
    d->spacings[0] = d->spacings[1] = spacing;
    invalidate();
}

/*!
    Returns the default horizontal spacing for the anchor layout.

    \sa verticalSpacing, setHorizontalSpacing
*/
qreal QGraphicsAnchorLayout::horizontalSpacing() const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->effectiveSpacing(QGraphicsAnchorLayoutPrivate::Horizontal);
}

/*!
    Returns the default vertical spacing for the anchor layout.

    \sa horizontalSpacing, setVerticalSpacing
*/
qreal QGraphicsAnchorLayout::verticalSpacing() const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->effectiveSpacing(QGraphicsAnchorLayoutPrivate::Vertical);
}

void QGraphicsAnchorLayout::setGeometry(const QRectF &geom)
{
    Q_D(QGraphicsAnchorLayout);

    // ### REMOVE IT WHEN calculateVertexPositions and setItemsGeometries are
    // simplification compatible!
    d->restoreSimplifiedGraph(QGraphicsAnchorLayoutPrivate::Horizontal);
    d->restoreSimplifiedGraph(QGraphicsAnchorLayoutPrivate::Vertical);

    QGraphicsLayout::setGeometry(geom);
    d->calculateVertexPositions(QGraphicsAnchorLayoutPrivate::Horizontal);
    d->calculateVertexPositions(QGraphicsAnchorLayoutPrivate::Vertical);
    d->setItemsGeometries();
}

void QGraphicsAnchorLayout::removeAt(int index)
{
    Q_D(QGraphicsAnchorLayout);
    QGraphicsLayoutItem *item = d->items.value(index);

    if (!item)
        return;

    // Removing an item affects both horizontal and vertical graphs
    d->restoreSimplifiedGraph(QGraphicsAnchorLayoutPrivate::Horizontal);
    d->restoreSimplifiedGraph(QGraphicsAnchorLayoutPrivate::Vertical);

    d->removeCenterConstraints(item, QGraphicsAnchorLayoutPrivate::Horizontal);
    d->removeCenterConstraints(item, QGraphicsAnchorLayoutPrivate::Vertical);
    d->removeAnchors(item);
    d->items.remove(index);

    item->setParentLayoutItem(0);
    invalidate();
}

int QGraphicsAnchorLayout::count() const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->items.size();
}

QGraphicsLayoutItem *QGraphicsAnchorLayout::itemAt(int index) const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->items.value(index);
}

void QGraphicsAnchorLayout::invalidate()
{
    Q_D(QGraphicsAnchorLayout);
    QGraphicsLayout::invalidate();
    d->calculateGraphCacheDirty = 1;
}

QSizeF QGraphicsAnchorLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    Q_UNUSED(which);
    Q_UNUSED(constraint);
    Q_D(const QGraphicsAnchorLayout);

    // Some setup calculations are delayed until the information is
    // actually needed, avoiding unnecessary recalculations when
    // adding multiple anchors.

    // sizeHint() / effectiveSizeHint() already have a cache
    // mechanism, using invalidate() to force recalculation. However
    // sizeHint() is called three times after invalidation (for max,
    // min and pref), but we just need do our setup once.

    const_cast<QGraphicsAnchorLayoutPrivate *>(d)->calculateGraphs();

    // ### apply constraint!
    QSizeF engineSizeHint(
        d->sizeHints[QGraphicsAnchorLayoutPrivate::Horizontal][which],
        d->sizeHints[QGraphicsAnchorLayoutPrivate::Vertical][which]);

    qreal left, top, right, bottom;
    getContentsMargins(&left, &top, &right, &bottom);

    return engineSizeHint + QSizeF(left + right, top + bottom);
}
<commit_msg>Fill in some missing pieces in the documentation.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \class QGraphicsAnchorLayout
    \brief The QGraphicsAnchorLayout class provides a layout where one can anchor widgets
    together in Graphics View.
    \since 4.6
    \ingroup appearance
    \ingroup geomanagement
    \ingroup graphicsview-api

    The anchor layout is a layout where one can specify how widgets should be placed relative to
    each other. The specification is called an anchor, and it is set up by calling anchor().
    Anchors are always set up between edges of an item, where the "center" is also considered to
    be an edge. Considering this example:
    \code
        QGraphicsAnchorLayout *l = new QGraphicsAnchorLayout;
        QGraphicsWidget *a = new QGraphicsWidget;
        QGraphicsWidget *b = new QGraphicsWidget;
        l->anchor(a, QGraphicsAnchorLayout::Right, b, QGraphicsAnchorLayout::Left);
    \endcode

    Here is the right edge of item A anchored to the left edge of item B, with the result that
    item B will be placed to the right of item A, with a spacing between A and B. If the
    spacing is negative, the items will overlap to some extent. Items that are anchored are
    automatically added to the layout, and if items are removed, all their anchors will be
    automatically removed

    \section1 Size Hints and Size Policies in QGraphicsLinearLayout
    QGraphicsLinearLayout respects each item's size hints and size policies. However it does
    not respect stretch factors currently. This might change in the future, so please refrain
    from using stretch factors in anchor layout to avoid any future regressions.

    \section1 Spacing within QGraphicsAnchorLayout

    Between the items, the layout can distribute some space. If the spacing has not been
    explicitly specified, the actual amount of space will usually be 0, but if the first edge
    is the "opposite" of the second edge (i.e. Right is anchored to Left or vice-versa), the
    size of the anchor will be queried from the style through the pixelMetric
    PM_LayoutHorizontalSpacing (or PM_LayoutVerticalSpacing for vertical anchors).
*/

#include "qgraphicsanchorlayout_p.h"

QGraphicsAnchorLayout::QGraphicsAnchorLayout(QGraphicsLayoutItem *parent)
    : QGraphicsLayout(*new QGraphicsAnchorLayoutPrivate(), parent)
{
    Q_D(QGraphicsAnchorLayout);
    d->createLayoutEdges();
}

QGraphicsAnchorLayout::~QGraphicsAnchorLayout()
{
    Q_D(QGraphicsAnchorLayout);

    for (int i = count() - 1; i >= 0; --i) {
        QGraphicsLayoutItem *item = d->items.at(i);
        removeAt(i);
        if (item) {
            if (item->ownedByLayout())
                delete item;
        }
    }

    d->removeCenterConstraints(this, QGraphicsAnchorLayoutPrivate::Horizontal);
    d->removeCenterConstraints(this, QGraphicsAnchorLayoutPrivate::Vertical);
    d->deleteLayoutEdges();

    Q_ASSERT(d->itemCenterConstraints[0].isEmpty());
    Q_ASSERT(d->itemCenterConstraints[1].isEmpty());
    Q_ASSERT(d->items.isEmpty());
    Q_ASSERT(d->m_vertexList.isEmpty());
}

/*!
 * Creates an anchor between the edge \a firstEdge of item \a firstItem and the edge \a secondEdge
 * of item \a secondItem. The magnitude of the anchor is picked up from the style. Anchors
 * between  a layout edge and an item edge will have a size of 0.
 * If there is already an anchor between the edges, the the new anchor will replace the old one.
 *
 * \a firstItem and \a secondItem are automatically added to the layout if they are not part
 * of the layout. This means that count() can increase with up to 2.
 *
 * The spacing an anchor will get depends on the type of anchor. For instance, anchors from the
 * Right edge of one item to the Left edge of another (or vice versa) will use the default
 * horizontal spacing. The same behaviour applies to Bottom to Top anchors, (but they will use
 * the default vertical spacing). For all other anchor combinations, the spacing will be 0.
 * All anchoring functions will follow this rule.
 *
 * \sa removeAnchor, anchorCorner, anchorWidth, anchorHeight, anchorGeometry
 */
void QGraphicsAnchorLayout::anchor(QGraphicsLayoutItem *firstItem,
                                   Edge firstEdge,
                                   QGraphicsLayoutItem *secondItem,
                                   Edge secondEdge)
{
    Q_D(QGraphicsAnchorLayout);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge);
    invalidate();
}

/*!
 * \overload
 *
 * By calling this function the caller can specify the magnitude of the anchor with \a spacing.
 *
 */
void QGraphicsAnchorLayout::anchor(QGraphicsLayoutItem *firstItem,
                                   Edge firstEdge,
                                   QGraphicsLayoutItem *secondItem,
                                   Edge secondEdge, qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge, &spacing);
    invalidate();
}

/*!
 * Creates two anchors between \a firstItem and \a secondItem, where one is for the horizontal
 * edge and another one for the vertical edge that the corners \a firstCorner and \a
 * secondCorner specifies.
 * The magnitude of the anchors is picked up from the style.
 *
 * This is a convenience function, since anchoring corners can be expressed as anchoring two edges.
 * For instance,
 * \code
 *  layout->anchor(layout, QGraphicsAnchorLayout::Top, b, QGraphicsAnchorLayout::Top);
 *  layout->anchor(layout, QGraphicsAnchorLayout::Left, b, QGraphicsAnchorLayout::Left);
 * \endcode
 *
 * has the same effect as
 *
 * \code
 * layout->anchorCorner(layout, Qt::TopLeft, b, Qt::TopLeft);
 * \endcode
 *
 * If there is already an anchor between the edge pairs, it will be replaced by the anchors that
 * this function specifies.
 *
 * \a firstItem and \a secondItem are automatically added to the layout if they are not part
 * of the layout. This means that count() can increase with up to 2.
 */
void QGraphicsAnchorLayout::anchorCorner(QGraphicsLayoutItem *firstItem,
                                         Qt::Corner firstCorner,
                                         QGraphicsLayoutItem *secondItem,
                                         Qt::Corner secondCorner)
{
    Q_D(QGraphicsAnchorLayout);

    // Horizontal anchor
    QGraphicsAnchorLayout::Edge firstEdge = (firstCorner & 1 ? QGraphicsAnchorLayout::Right: QGraphicsAnchorLayout::Left);
    QGraphicsAnchorLayout::Edge secondEdge = (secondCorner & 1 ? QGraphicsAnchorLayout::Right: QGraphicsAnchorLayout::Left);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge);

    // Vertical anchor
    firstEdge = (firstCorner & 2 ? QGraphicsAnchorLayout::Bottom: QGraphicsAnchorLayout::Top);
    secondEdge = (secondCorner & 2 ? QGraphicsAnchorLayout::Bottom: QGraphicsAnchorLayout::Top);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge);

    invalidate();
}

/*!
 * \overload
 *
 * By calling this function the caller can specify the magnitude of the anchor with \a spacing.
 *
 */
void QGraphicsAnchorLayout::anchorCorner(QGraphicsLayoutItem *firstItem,
                                         Qt::Corner firstCorner,
                                         QGraphicsLayoutItem *secondItem,
                                         Qt::Corner secondCorner, qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);

    // Horizontal anchor
    QGraphicsAnchorLayout::Edge firstEdge = (firstCorner & 1 ? QGraphicsAnchorLayout::Right: QGraphicsAnchorLayout::Left);
    QGraphicsAnchorLayout::Edge secondEdge = (secondCorner & 1 ? QGraphicsAnchorLayout::Right: QGraphicsAnchorLayout::Left);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge, &spacing);

    // Vertical anchor
    firstEdge = (firstCorner & 2 ? QGraphicsAnchorLayout::Bottom: QGraphicsAnchorLayout::Top);
    secondEdge = (secondCorner & 2 ? QGraphicsAnchorLayout::Bottom: QGraphicsAnchorLayout::Top);
    d->anchor(firstItem, firstEdge, secondItem, secondEdge, &spacing);

    invalidate();
}

/*!
    \fn QGraphicsAnchorLayout::anchorWidth(QGraphicsLayoutItem *item, QGraphicsLayoutItem *relativeTo = 0)

    This convenience function is equivalent to calling
    \code
    if (!relativeTo)
        relativeTo = lay;
    lay->anchor(relativeTo, QGraphicsAnchorLayout::Left, item, QGraphicsAnchorLayout::Left);
    lay->anchor(relativeTo, QGraphicsAnchorLayout::Right, item, QGraphicsAnchorLayout::Right);
    \endcode
*/

/*!
    \fn QGraphicsAnchorLayout::anchorWidth(QGraphicsLayoutItem *item, QGraphicsLayoutItem *relativeTo, qreal spacing)

    \overload

    By calling this function the caller can specify the magnitude of the anchor with \a spacing.
*/

/*!
    \fn QGraphicsAnchorLayout::anchorHeight(QGraphicsLayoutItem *item, QGraphicsLayoutItem *relativeTo = 0)

    This convenience function is equivalent to calling
    \code
    if (!relativeTo)
        relativeTo = lay;
    lay->anchor(relativeTo, QGraphicsAnchorLayout::Top, item, QGraphicsAnchorLayout::Top);
    lay->anchor(relativeTo, QGraphicsAnchorLayout::Bottom, item, QGraphicsAnchorLayout::Bottom);
    \endcode
*/

/*!
    \fn QGraphicsAnchorLayout::anchorHeight(QGraphicsLayoutItem *item, QGraphicsLayoutItem *relativeTo, qreal spacing)

    \overload

    By calling this function the caller can specify the magnitude of the anchor with \a spacing.
*/

/*!
    \fn QGraphicsAnchorLayout::anchorGeometry(QGraphicsLayoutItem *item, QGraphicsLayoutItem *relativeTo = 0)

    This convenience function is equivalent to calling
    \code
    anchorWidth(item, relativeTo);
    anchorHeight(item, relativeTo);
    \endcode
*/

/*!
    \fn QGraphicsAnchorLayout::anchorGeometry(QGraphicsLayoutItem *item, QGraphicsLayoutItem *relativeTo, qreal spacing)

    \overload

    By calling this function the caller can specify the magnitude of the anchor with \a spacing.
*/

/*!
   Removes the anchor between the edge \a firstEdge of item \a firstItem and the edge \a secondEdge
   of item \a secondItem. If such an anchor does not exist, the layout will be left unchanged.
*/
void QGraphicsAnchorLayout::removeAnchor(QGraphicsLayoutItem *firstItem, Edge firstEdge,
                                         QGraphicsLayoutItem *secondItem, Edge secondEdge)
{
    Q_D(QGraphicsAnchorLayout);
    if ((firstItem == 0) || (secondItem == 0)) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor between NULL items");
        return;
    }

    if (firstItem == secondItem) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor from the item to itself");
        return;
    }

    if (d->edgeOrientation(secondEdge) != d->edgeOrientation(firstEdge)) {
        qWarning("QGraphicsAnchorLayout::removeAnchor: "
                 "Cannot remove anchor from edges of different orientations");
        return;
    }

    d->removeAnchor(firstItem, firstEdge, secondItem, secondEdge);
    invalidate();
}

/*!
    Sets the default horizontal spacing for the anchor layout to \a spacing.

    \sa horizontalSpacing, setVerticalSpacing, setSpacing
*/
void QGraphicsAnchorLayout::setHorizontalSpacing(qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);
    d->spacings[0] = spacing;
    invalidate();
}

/*!
    Sets the default vertical spacing for the anchor layout to \a spacing.

    \sa verticalSpacing, setHorizontalSpacing, setSpacing
*/
void QGraphicsAnchorLayout::setVerticalSpacing(qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);
    d->spacings[1] = spacing;
    invalidate();
}

/*!
    Sets the default horizontal and the default vertical spacing for the anchor layout to \a spacing.

    If an item is anchored with no spacing associated with the anchor, it will use the default
    spacing.
    \sa setHorizontalSpacing, setVerticalSpacing
*/
void QGraphicsAnchorLayout::setSpacing(qreal spacing)
{
    Q_D(QGraphicsAnchorLayout);
    d->spacings[0] = d->spacings[1] = spacing;
    invalidate();
}

/*!
    Returns the default horizontal spacing for the anchor layout.

    \sa verticalSpacing, setHorizontalSpacing
*/
qreal QGraphicsAnchorLayout::horizontalSpacing() const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->effectiveSpacing(QGraphicsAnchorLayoutPrivate::Horizontal);
}

/*!
    Returns the default vertical spacing for the anchor layout.

    \sa horizontalSpacing, setVerticalSpacing
*/
qreal QGraphicsAnchorLayout::verticalSpacing() const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->effectiveSpacing(QGraphicsAnchorLayoutPrivate::Vertical);
}

/*!
  \reimp
*/
void QGraphicsAnchorLayout::setGeometry(const QRectF &geom)
{
    Q_D(QGraphicsAnchorLayout);

    // ### REMOVE IT WHEN calculateVertexPositions and setItemsGeometries are
    // simplification compatible!
    d->restoreSimplifiedGraph(QGraphicsAnchorLayoutPrivate::Horizontal);
    d->restoreSimplifiedGraph(QGraphicsAnchorLayoutPrivate::Vertical);

    QGraphicsLayout::setGeometry(geom);
    d->calculateVertexPositions(QGraphicsAnchorLayoutPrivate::Horizontal);
    d->calculateVertexPositions(QGraphicsAnchorLayoutPrivate::Vertical);
    d->setItemsGeometries();
}

/*!
    Removing an item will also remove any of the anchors associated with it.
*/
void QGraphicsAnchorLayout::removeAt(int index)
{
    Q_D(QGraphicsAnchorLayout);
    QGraphicsLayoutItem *item = d->items.value(index);

    if (!item)
        return;

    // Removing an item affects both horizontal and vertical graphs
    d->restoreSimplifiedGraph(QGraphicsAnchorLayoutPrivate::Horizontal);
    d->restoreSimplifiedGraph(QGraphicsAnchorLayoutPrivate::Vertical);

    d->removeCenterConstraints(item, QGraphicsAnchorLayoutPrivate::Horizontal);
    d->removeCenterConstraints(item, QGraphicsAnchorLayoutPrivate::Vertical);
    d->removeAnchors(item);
    d->items.remove(index);

    item->setParentLayoutItem(0);
    invalidate();
}

/*!
    \reimp
*/
int QGraphicsAnchorLayout::count() const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->items.size();
}

/*!
    \reimp
*/
QGraphicsLayoutItem *QGraphicsAnchorLayout::itemAt(int index) const
{
    Q_D(const QGraphicsAnchorLayout);
    return d->items.value(index);
}

/*!
    \reimp
*/
void QGraphicsAnchorLayout::invalidate()
{
    Q_D(QGraphicsAnchorLayout);
    QGraphicsLayout::invalidate();
    d->calculateGraphCacheDirty = 1;
}

/*!
    \reimp
*/
QSizeF QGraphicsAnchorLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    Q_UNUSED(which);
    Q_UNUSED(constraint);
    Q_D(const QGraphicsAnchorLayout);

    // Some setup calculations are delayed until the information is
    // actually needed, avoiding unnecessary recalculations when
    // adding multiple anchors.

    // sizeHint() / effectiveSizeHint() already have a cache
    // mechanism, using invalidate() to force recalculation. However
    // sizeHint() is called three times after invalidation (for max,
    // min and pref), but we just need do our setup once.

    const_cast<QGraphicsAnchorLayoutPrivate *>(d)->calculateGraphs();

    // ### apply constraint!
    QSizeF engineSizeHint(
        d->sizeHints[QGraphicsAnchorLayoutPrivate::Horizontal][which],
        d->sizeHints[QGraphicsAnchorLayoutPrivate::Vertical][which]);

    qreal left, top, right, bottom;
    getContentsMargins(&left, &top, &right, &bottom);

    return engineSizeHint + QSizeF(left + right, top + bottom);
}
<|endoftext|>