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

  Program:   Visualization Toolkit
  Module:    vtkRTAnalyticSource.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

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

#include "vtkDataArray.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkPointData.h"

#include <cmath>

vtkStandardNewMacro(vtkRTAnalyticSource);

// ----------------------------------------------------------------------------
vtkRTAnalyticSource::vtkRTAnalyticSource()
{
  this->Maximum = 255.0;
  this->Center[0] = 0.0;
  this->Center[1] = 0.0;
  this->Center[2] = 0.0;

  this->WholeExtent[0] = -10;  this->WholeExtent[1] = 10;
  this->WholeExtent[2] = -10;  this->WholeExtent[3] = 10;
  this->WholeExtent[4] = -10;  this->WholeExtent[5] = 10;
  this->StandardDeviation = 0.5;

  this->XFreq = 60;
  this->XMag = 10;
  this->YFreq = 30;
  this->YMag = 18;
  this->ZFreq = 40;
  this->ZMag = 5;

  this->SetNumberOfInputPorts(0);

  this->SubsampleRate = 1;
}

// ----------------------------------------------------------------------------
void vtkRTAnalyticSource::SetWholeExtent(int xMin, int xMax,
                                         int yMin, int yMax,
                                         int zMin, int zMax)
{
  int modified = 0;

  if (this->WholeExtent[0] != xMin)
    {
    modified = 1;
    this->WholeExtent[0] = xMin ;
    }
  if (this->WholeExtent[1] != xMax)
    {
    modified = 1;
    this->WholeExtent[1] = xMax ;
    }
  if (this->WholeExtent[2] != yMin)
    {
    modified = 1;
    this->WholeExtent[2] = yMin ;
    }
  if (this->WholeExtent[3] != yMax)
    {
    modified = 1;
    this->WholeExtent[3] = yMax ;
    }
  if (this->WholeExtent[4] != zMin)
    {
    modified = 1;
    this->WholeExtent[4] = zMin ;
    }
  if (this->WholeExtent[5] != zMax)
    {
    modified = 1;
    this->WholeExtent[5] = zMax ;
    }
  if (modified)
    {
    this->Modified();
    }
}

// ----------------------------------------------------------------------------
int vtkRTAnalyticSource::RequestInformation(
   vtkInformation *vtkNotUsed(request),
   vtkInformationVector **vtkNotUsed(inputVector),
   vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  int tmpExt[6], i;
  for (i = 0; i < 3; i++)
    {
    tmpExt[2*i] = this->WholeExtent[2*i] / this->SubsampleRate;
    tmpExt[2*i+1] = this->WholeExtent[2*i+1] / this->SubsampleRate;
    }

  outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
               tmpExt,6);

  outInfo->Set(vtkDataObject::ORIGIN(),  0.0, 0.0, 0.0);
  outInfo->Set(vtkDataObject::SPACING(), this->SubsampleRate,
               this->SubsampleRate, this->SubsampleRate);
  vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_FLOAT, 1);

  outInfo->Set(CAN_PRODUCE_SUB_EXTENT(), 1);

  return 1;
}

void vtkRTAnalyticSource::ExecuteDataWithInformation(vtkDataObject *vtkNotUsed(output),
                                                     vtkInformation *outInfo)
{
  float *outPtr;
  int idxX, idxY, idxZ;
  int maxX, maxY, maxZ;
  vtkIdType outIncX, outIncY, outIncZ;
  int *outExt, *whlExt;
  int newOutExt[6];
  double sum;
  double yContrib, zContrib;
  double temp2;
  unsigned long count = 0;
  unsigned long target;

  // Split the update extent further based on piece request.
  int* execExt = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());

  // For debugging
  /*
  int numPieces = outInfo->Get(
    vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
  int piece = outInfo->Get(
    vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
  int numGhosts = outInfo->Get(
    vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS());

  if (piece == 0)
    {
    cout << "Piece:" << piece << " " << numPieces << " " << numGhosts << endl;
    cout << "Extent: "
         << execExt[0] << " "
         << execExt[1] << " "
         << execExt[2] << " "
         << execExt[3] << " "
         << execExt[4] << " "
         << execExt[5] << endl;
    }
  */

  vtkImageData *data = vtkImageData::GetData(outInfo);
  this->AllocateOutputData(data, outInfo, execExt);
  if (data->GetScalarType() != VTK_FLOAT)
    {
    vtkErrorMacro("Execute: This source only outputs floats");
    return;
    }
  if (data->GetNumberOfPoints() <= 0)
    {
    return;
    }

  data->SetSpacing(this->SubsampleRate, this->SubsampleRate,
                   this->SubsampleRate);

  outExt = data->GetExtent();
  int i;
  for (i = 0; i < 3; i++)
    {
    newOutExt[2*i] = outExt[2*i] * this->SubsampleRate;
    newOutExt[2*i+1] = outExt[2*i+1] * this->SubsampleRate;
    }
  whlExt = this->GetWholeExtent();
  data->GetPointData()->GetScalars()->SetName("RTData");

  // find the region to loop over
  maxX = newOutExt[1] - newOutExt[0];
  maxY = newOutExt[3] - newOutExt[2];
  maxZ = newOutExt[5] - newOutExt[4];

  // Get increments to march through data
  data->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);
  outPtr = static_cast<float *>(data->GetScalarPointer(outExt[0],outExt[2],outExt[4]));

  target = static_cast<unsigned long>((maxZ+1)*(maxY+1)/50.0);
  target++;

  // Loop through output pixels
  temp2 = 1.0 / (2.0 * this->StandardDeviation * this->StandardDeviation);

  double x, y, z;
  const double xscale = (whlExt[1] > whlExt[0])? (1.0/(whlExt[1] - whlExt[0])) : 1.0;
  const double yscale = (whlExt[3] > whlExt[2])? (1.0/(whlExt[3] - whlExt[2])) : 1.0;
  const double zscale = (whlExt[5] > whlExt[4])? (1.0/(whlExt[5] - whlExt[4])) : 1.0;
  for (idxZ = 0; idxZ <= maxZ; idxZ++)
    {
    if ((this->SubsampleRate > 1) && (idxZ % this->SubsampleRate))
      {
      continue;
      }
    z = this->Center[2] - (idxZ + newOutExt[4]);
    z *= zscale;
    zContrib = z * z;
    const float zfactor = static_cast<float>(this->ZMag*cos(this->ZFreq*z));
    for (idxY = 0; !this->AbortExecute && idxY <= maxY; idxY++)
      {
      if ((this->SubsampleRate > 1) && (idxY % this->SubsampleRate))
        {
        continue;
        }
      if (!(count%target))
        {
        this->UpdateProgress(count/(50.0*target));
        }
      count++;
      y = this->Center[1] - (idxY + newOutExt[2]);
      y *= yscale;
      yContrib = y * y;
      const float yfactor = static_cast<float>(this->YMag*sin(this->YFreq*y));
      for (idxX = 0; idxX <= maxX; idxX++)
        {
        if ((this->SubsampleRate > 1) && (idxX % this->SubsampleRate))
          {
          continue;
          }
        // Pixel operation
        sum = zContrib + yContrib;
        x = this->Center[0] - (idxX + newOutExt[0]);
        x *= xscale;
        sum = sum + (x * x);
        const float xfactor = static_cast<float>(this->XMag*sin(this->XFreq*x));
        *outPtr = this->Maximum * exp(-sum * temp2)
          + xfactor /*this->XMag*sin(this->XFreq*x)*/
          + yfactor /*this->YMag*sin(this->YFreq*y)*/
          + zfactor /*this->ZMag*cos(this->ZFreq*z)*/;
        outPtr++;
        }
      outPtr += outIncY;
      }
    outPtr += outIncZ;
    }
}

void vtkRTAnalyticSource::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Maximum: " << this->Maximum << "\n";
  os << indent << "StandardDeviation: " << this->StandardDeviation << "\n";
  os << indent << "Center: ( "
     << this->Center[0] << ", "
     << this->Center[1] << ", "
     << this->Center[2] << " )\n";
  os << indent << "XFreq: " << this->XFreq << endl;
  os << indent << "YFreq: " << this->YFreq << endl;
  os << indent << "ZFreq: " << this->ZFreq << endl;
  os << indent << "XMag: " << this->XMag << endl;
  os << indent << "YMag: " << this->YMag << endl;
  os << indent << "ZMag: " << this->ZMag << endl;

  os << indent << "WholeExtent: " << this->WholeExtent[0]
     << ", " << this->WholeExtent[1] << ", " << this->WholeExtent[2]
     << ", " << this->WholeExtent[3] << ", " << this->WholeExtent[4]
     << ", " << this->WholeExtent[5] << endl;

  os << indent << "SubsampleRate: " << this->SubsampleRate << endl;
}

int vtkRTAnalyticSource::FillOutputPortInformation(
  int port, vtkInformation* info)
{
  if (!this->Superclass::FillOutputPortInformation(port, info))
    {
    return 0;
    }

  return 1;
}
<commit_msg>Validate whole extent specified on vtkRTAnalyticSource.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkRTAnalyticSource.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

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

#include "vtkDataArray.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkPointData.h"

#include <cmath>

vtkStandardNewMacro(vtkRTAnalyticSource);

// ----------------------------------------------------------------------------
vtkRTAnalyticSource::vtkRTAnalyticSource()
{
  this->Maximum = 255.0;
  this->Center[0] = 0.0;
  this->Center[1] = 0.0;
  this->Center[2] = 0.0;

  this->WholeExtent[0] = -10;  this->WholeExtent[1] = 10;
  this->WholeExtent[2] = -10;  this->WholeExtent[3] = 10;
  this->WholeExtent[4] = -10;  this->WholeExtent[5] = 10;
  this->StandardDeviation = 0.5;

  this->XFreq = 60;
  this->XMag = 10;
  this->YFreq = 30;
  this->YMag = 18;
  this->ZFreq = 40;
  this->ZMag = 5;

  this->SetNumberOfInputPorts(0);

  this->SubsampleRate = 1;
}

// ----------------------------------------------------------------------------
void vtkRTAnalyticSource::SetWholeExtent(int xMin, int xMax,
                                         int yMin, int yMax,
                                         int zMin, int zMax)
{
  int modified = 0;

  if (this->WholeExtent[0] != xMin)
    {
    modified = 1;
    this->WholeExtent[0] = xMin ;
    }
  if (this->WholeExtent[1] != xMax)
    {
    modified = 1;
    this->WholeExtent[1] = xMax ;
    }
  if (this->WholeExtent[2] != yMin)
    {
    modified = 1;
    this->WholeExtent[2] = yMin ;
    }
  if (this->WholeExtent[3] != yMax)
    {
    modified = 1;
    this->WholeExtent[3] = yMax ;
    }
  if (this->WholeExtent[4] != zMin)
    {
    modified = 1;
    this->WholeExtent[4] = zMin ;
    }
  if (this->WholeExtent[5] != zMax)
    {
    modified = 1;
    this->WholeExtent[5] = zMax ;
    }
  if (modified)
    {
    this->Modified();
    }
}

// ----------------------------------------------------------------------------
int vtkRTAnalyticSource::RequestInformation(
   vtkInformation *vtkNotUsed(request),
   vtkInformationVector **vtkNotUsed(inputVector),
   vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *outInfo = outputVector->GetInformationObject(0);
  if (this->WholeExtent[0] > this->WholeExtent[1] ||
    this->WholeExtent[2] > this->WholeExtent[3] ||
    this->WholeExtent[4] > this->WholeExtent[5])
    {
    vtkErrorMacro("Invalid WholeExtent: "
      << this->WholeExtent[0] << ", " << this->WholeExtent[1] << ", "
      << this->WholeExtent[2] << ", " << this->WholeExtent[3] << ", "
      << this->WholeExtent[4] << ", " << this->WholeExtent[5]);
    return 0;
    }

  int tmpExt[6], i;
  for (i = 0; i < 3; i++)
    {
    tmpExt[2*i] = this->WholeExtent[2*i] / this->SubsampleRate;
    tmpExt[2*i+1] = this->WholeExtent[2*i+1] / this->SubsampleRate;
    }

  outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),
               tmpExt,6);

  outInfo->Set(vtkDataObject::ORIGIN(),  0.0, 0.0, 0.0);
  outInfo->Set(vtkDataObject::SPACING(), this->SubsampleRate,
               this->SubsampleRate, this->SubsampleRate);
  vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_FLOAT, 1);

  outInfo->Set(CAN_PRODUCE_SUB_EXTENT(), 1);

  return 1;
}

void vtkRTAnalyticSource::ExecuteDataWithInformation(vtkDataObject *vtkNotUsed(output),
                                                     vtkInformation *outInfo)
{
  float *outPtr;
  int idxX, idxY, idxZ;
  int maxX, maxY, maxZ;
  vtkIdType outIncX, outIncY, outIncZ;
  int *outExt, *whlExt;
  int newOutExt[6];
  double sum;
  double yContrib, zContrib;
  double temp2;
  unsigned long count = 0;
  unsigned long target;

  // Split the update extent further based on piece request.
  int* execExt = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());

  // For debugging
  /*
  int numPieces = outInfo->Get(
    vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
  int piece = outInfo->Get(
    vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
  int numGhosts = outInfo->Get(
    vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS());

  if (piece == 0)
    {
    cout << "Piece:" << piece << " " << numPieces << " " << numGhosts << endl;
    cout << "Extent: "
         << execExt[0] << " "
         << execExt[1] << " "
         << execExt[2] << " "
         << execExt[3] << " "
         << execExt[4] << " "
         << execExt[5] << endl;
    }
  */

  vtkImageData *data = vtkImageData::GetData(outInfo);
  this->AllocateOutputData(data, outInfo, execExt);
  if (data->GetScalarType() != VTK_FLOAT)
    {
    vtkErrorMacro("Execute: This source only outputs floats");
    return;
    }
  if (data->GetNumberOfPoints() <= 0)
    {
    return;
    }

  data->SetSpacing(this->SubsampleRate, this->SubsampleRate,
                   this->SubsampleRate);

  outExt = data->GetExtent();
  int i;
  for (i = 0; i < 3; i++)
    {
    newOutExt[2*i] = outExt[2*i] * this->SubsampleRate;
    newOutExt[2*i+1] = outExt[2*i+1] * this->SubsampleRate;
    }
  whlExt = this->GetWholeExtent();
  data->GetPointData()->GetScalars()->SetName("RTData");

  // find the region to loop over
  maxX = newOutExt[1] - newOutExt[0];
  maxY = newOutExt[3] - newOutExt[2];
  maxZ = newOutExt[5] - newOutExt[4];

  // Get increments to march through data
  data->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ);
  outPtr = static_cast<float *>(data->GetScalarPointer(outExt[0],outExt[2],outExt[4]));

  target = static_cast<unsigned long>((maxZ+1)*(maxY+1)/50.0);
  target++;

  // Loop through output pixels
  temp2 = 1.0 / (2.0 * this->StandardDeviation * this->StandardDeviation);

  double x, y, z;
  const double xscale = (whlExt[1] > whlExt[0])? (1.0/(whlExt[1] - whlExt[0])) : 1.0;
  const double yscale = (whlExt[3] > whlExt[2])? (1.0/(whlExt[3] - whlExt[2])) : 1.0;
  const double zscale = (whlExt[5] > whlExt[4])? (1.0/(whlExt[5] - whlExt[4])) : 1.0;
  for (idxZ = 0; idxZ <= maxZ; idxZ++)
    {
    if ((this->SubsampleRate > 1) && (idxZ % this->SubsampleRate))
      {
      continue;
      }
    z = this->Center[2] - (idxZ + newOutExt[4]);
    z *= zscale;
    zContrib = z * z;
    const float zfactor = static_cast<float>(this->ZMag*cos(this->ZFreq*z));
    for (idxY = 0; !this->AbortExecute && idxY <= maxY; idxY++)
      {
      if ((this->SubsampleRate > 1) && (idxY % this->SubsampleRate))
        {
        continue;
        }
      if (!(count%target))
        {
        this->UpdateProgress(count/(50.0*target));
        }
      count++;
      y = this->Center[1] - (idxY + newOutExt[2]);
      y *= yscale;
      yContrib = y * y;
      const float yfactor = static_cast<float>(this->YMag*sin(this->YFreq*y));
      for (idxX = 0; idxX <= maxX; idxX++)
        {
        if ((this->SubsampleRate > 1) && (idxX % this->SubsampleRate))
          {
          continue;
          }
        // Pixel operation
        sum = zContrib + yContrib;
        x = this->Center[0] - (idxX + newOutExt[0]);
        x *= xscale;
        sum = sum + (x * x);
        const float xfactor = static_cast<float>(this->XMag*sin(this->XFreq*x));
        *outPtr = this->Maximum * exp(-sum * temp2)
          + xfactor /*this->XMag*sin(this->XFreq*x)*/
          + yfactor /*this->YMag*sin(this->YFreq*y)*/
          + zfactor /*this->ZMag*cos(this->ZFreq*z)*/;
        outPtr++;
        }
      outPtr += outIncY;
      }
    outPtr += outIncZ;
    }
}

void vtkRTAnalyticSource::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Maximum: " << this->Maximum << "\n";
  os << indent << "StandardDeviation: " << this->StandardDeviation << "\n";
  os << indent << "Center: ( "
     << this->Center[0] << ", "
     << this->Center[1] << ", "
     << this->Center[2] << " )\n";
  os << indent << "XFreq: " << this->XFreq << endl;
  os << indent << "YFreq: " << this->YFreq << endl;
  os << indent << "ZFreq: " << this->ZFreq << endl;
  os << indent << "XMag: " << this->XMag << endl;
  os << indent << "YMag: " << this->YMag << endl;
  os << indent << "ZMag: " << this->ZMag << endl;

  os << indent << "WholeExtent: " << this->WholeExtent[0]
     << ", " << this->WholeExtent[1] << ", " << this->WholeExtent[2]
     << ", " << this->WholeExtent[3] << ", " << this->WholeExtent[4]
     << ", " << this->WholeExtent[5] << endl;

  os << indent << "SubsampleRate: " << this->SubsampleRate << endl;
}

int vtkRTAnalyticSource::FillOutputPortInformation(
  int port, vtkInformation* info)
{
  if (!this->Superclass::FillOutputPortInformation(port, info))
    {
    return 0;
    }

  return 1;
}
<|endoftext|>


<commit_before>
#include "vtkActor.h"
#include "vtkFast2DLayoutStrategy.h"
#include "vtkForceDirectedLayoutStrategy.h"
#include "vtkGraphLayout.h"
#include "vtkGraphToPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRandomGraphSource.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSmartPointer.h"
#include "vtkTestUtilities.h"
#include "vtkVertexGlyphFilter.h"

#define VTK_CREATE(type,name) \
  vtkSmartPointer<type> name = vtkSmartPointer<type>::New()

int TestArcEdges(int argc, char* argv[])
{
  VTK_CREATE(vtkRandomGraphSource, source);
  VTK_CREATE(vtkGraphLayout, layout);
  VTK_CREATE(vtkFast2DLayoutStrategy, strategy);
  VTK_CREATE(vtkGraphToPolyData, graphToPoly);
  VTK_CREATE(vtkPolyDataMapper, edgeMapper);
  VTK_CREATE(vtkActor, edgeActor);
  VTK_CREATE(vtkGraphToPolyData, graphToPoints);
  VTK_CREATE(vtkVertexGlyphFilter, vertGlyph);
  VTK_CREATE(vtkPolyDataMapper, vertMapper);
  VTK_CREATE(vtkActor, vertActor);
  VTK_CREATE(vtkRenderer, ren);
  VTK_CREATE(vtkRenderWindow, win);
  VTK_CREATE(vtkRenderWindowInteractor, iren);

  source->SetNumberOfVertices(3);
  source->SetNumberOfEdges(50);
  source->AllowSelfLoopsOn();
  source->AllowParallelEdgesOn();
  source->StartWithTreeOff();
  source->DirectedOff();
  layout->SetInputConnection(source->GetOutputPort());
  layout->SetLayoutStrategy(strategy);
  graphToPoly->SetInputConnection(layout->GetOutputPort());
  graphToPoly->ArcEdgesOn();
  graphToPoly->SetNumberOfArcSubdivisions(50);
  edgeMapper->SetInputConnection(graphToPoly->GetOutputPort());
  edgeActor->SetMapper(edgeMapper);
  ren->AddActor(edgeActor);

  graphToPoints->SetInputConnection(layout->GetOutputPort());
  vertGlyph->SetInputConnection(graphToPoints->GetOutputPort());
  vertMapper->SetInputConnection(vertGlyph->GetOutputPort());
  vertActor->SetMapper(vertMapper);
  vertActor->GetProperty()->SetPointSize(10);
  ren->AddActor(vertActor);

  win->AddRenderer(ren);
  win->SetInteractor(iren);
  win->Render();

  int retVal = vtkRegressionTestImage(win);
  if (retVal == vtkRegressionTester::DO_INTERACTOR)
    {
    iren->Initialize();
    iren->Start();

    retVal = vtkRegressionTester::PASSED;
    }

  return !retVal;
}

<commit_msg>ENH: Checking in new TestArcEdges that should produce the same image on most all platforms.<commit_after>
#include "vtkActor.h"
#include "vtkCircularLayoutStrategy.h"
#include "vtkForceDirectedLayoutStrategy.h"
#include "vtkGraphLayout.h"
#include "vtkGraphToPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRandomGraphSource.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSmartPointer.h"
#include "vtkTestUtilities.h"
#include "vtkVertexGlyphFilter.h"

#define VTK_CREATE(type,name) \
  vtkSmartPointer<type> name = vtkSmartPointer<type>::New()

int TestArcEdges(int argc, char* argv[])
{
  VTK_CREATE(vtkRandomGraphSource, source);
  VTK_CREATE(vtkGraphLayout, layout);
  VTK_CREATE(vtkCircularLayoutStrategy, strategy);
  VTK_CREATE(vtkGraphToPolyData, graphToPoly);
  VTK_CREATE(vtkPolyDataMapper, edgeMapper);
  VTK_CREATE(vtkActor, edgeActor);
  VTK_CREATE(vtkGraphToPolyData, graphToPoints);
  VTK_CREATE(vtkVertexGlyphFilter, vertGlyph);
  VTK_CREATE(vtkPolyDataMapper, vertMapper);
  VTK_CREATE(vtkActor, vertActor);
  VTK_CREATE(vtkRenderer, ren);
  VTK_CREATE(vtkRenderWindow, win);
  VTK_CREATE(vtkRenderWindowInteractor, iren);

  source->SetNumberOfVertices(3);
  source->SetNumberOfEdges(50);
  source->AllowSelfLoopsOn();
  source->AllowParallelEdgesOn();
  source->StartWithTreeOff();
  source->DirectedOff();
  layout->SetInputConnection(source->GetOutputPort());
  layout->SetLayoutStrategy(strategy);
  graphToPoly->SetInputConnection(layout->GetOutputPort());
  graphToPoly->ArcEdgesOn();
  graphToPoly->SetNumberOfArcSubdivisions(50);
  edgeMapper->SetInputConnection(graphToPoly->GetOutputPort());
  edgeActor->SetMapper(edgeMapper);
  ren->AddActor(edgeActor);

  graphToPoints->SetInputConnection(layout->GetOutputPort());
  vertGlyph->SetInputConnection(graphToPoints->GetOutputPort());
  vertMapper->SetInputConnection(vertGlyph->GetOutputPort());
  vertActor->SetMapper(vertMapper);
  vertActor->GetProperty()->SetPointSize(1);
  ren->AddActor(vertActor);

  win->AddRenderer(ren);
  win->SetInteractor(iren);
  win->Render();

  int retVal = vtkRegressionTestImage(win);
  if (retVal == vtkRegressionTester::DO_INTERACTOR)
    {
    iren->Initialize();
    iren->Start();

    retVal = vtkRegressionTester::PASSED;
    }

  return !retVal;
}

<|endoftext|>


<commit_before>// Copyright (c) 2017 nyorain
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt

///  file Contains the Span template class for not-owned contigous ranges.

#pragma once

#ifndef NYTL_INCLUDE_SPAN
#define NYTL_INCLUDE_SPAN

#include <nytl/fwd/span.hpp> // nytl::Span default template parameter
#include <nytl/scalar.hpp> // nytl::constants::dynamicSize

#include <cstdlib> // std::size_t
#include <stdexcept> // std::out_of_range
#include <array> // std::array

namespace nytl {
namespace detail {
	template<typename T, typename C, typename = void> struct ValidContainerT;
	template<typename T, typename C> using ValidContainer = typename ValidContainerT<T, C>::type;
} // namespace nytl::detail

/// The underlaying storage type of spans that is specialized for dyanmic size.
template<typename T, std::size_t N> struct SpanStorage;

/// \brief Describes a contigous, non-owned range of elements of type 'T'.
/// \details Spans can be used to pass sequences of elements around in a lightweight manner.
/// Its main use are function parameters sine instead of a std::vector it will not allocate
/// any memory or copy any elements but instead just reference them.
/// \tparam T The type the range is defined over. Use const types for non-mutable ranges.
/// \tparam N The size of the range. If not known at compile
/// time, use nytl::constants::dynamicSize (also defaulted to dynamicSize).
///
/// Some examples below. Note that Spans must be used carefully outside of temporary
/// expressions since they are only valid as long the object they reference is valid.
/// ```cpp
/// void foo(nytl::Span<std::string> names); // takes dyanmic amount of strings, might modify it
/// void bar(nytl::Span<const std::string, 3> names); // takes exactly 3 const strings
/// void baz(nytl::Span<const std::string, 5> names); // takes exactly 5 const strings
///
/// int main()
/// {
///		std::array<std::string, 3> namesArray {"foo", "bar", "baz"};
///		foo(namesArray); // works
/// 	bar(namesArray); // works
///		baz(namesArray); // will throw std::logic_error since baz requires exactly 5 strings
///
///		std::vector<std::string> namesVector {"foo", "bar", "baz", "abz", "bla"};
///		foo(namesVector); // works
///		bar(namesVector); // will throw std::logic_error since bar requires exactly 3 strings
///		baz(namesVector); // works
///
/// 	// If we only want the first 3 elements from namesVector as range we can do it like this
///		bar({namesVector.data(), 3}); // works, takes the first 3 elements
///		foo({*namesVector.data(), 4}); // we can also use references
///
///		// careful when using span outside of temporary expressions
///		auto span = nytl::Span<int>(std::vector<int>{4, 1, 2, 0});
/// 	// std::cout << span[0] << "\n"; // undefined behaviour!
/// }
///
/// void foo(nytl::Span<std::string> names)
/// {
///		// Some usage possibilities for span.
////	// The main usage is iterating over it:
///		for(auto& name : names)
///			std::cout << name << "\n";
///
///		// We might alternatively do this with a traditional for loop
///		for(auto i = 0u; i < names.size(); ++i)
///			std::cout << name << "\n";
///
///		// In this case we have a span of std::string, not const std::string,
///		// therefore we might also change it. This will change the names in the actual
///		// sequence this span references. Usually nytl::Span<const T> is used when the
///		// span is only read
///		if(!names.empty()) {
///			names.front() = "first name";
///			names.back() = "last name";
///		}
///
///		// A span can additionally be sliced into a subspan. This can either be
///		// done with a size known at compile time (which will result in a fixed-size span)
///		// or dynamically for a dynamic-sized span.
///		if(names.size() <= 2) return;
///		for(auto& name : names.slice(2, names.size() - 2)) // output everything but the first two
///			std::cout << name << "\n";
///
///		for(auto& name : names.slice<2>(0)) // output only the first two names
///			std::cout << name << "\n";
/// }
/// ```
template<typename T, std::size_t N>
class Span : public SpanStorage<T, N> {
public:
	using Value = T;
	using Iterator = T*;
	using ReverseIterator = std::reverse_iterator<T*>;
	using Reference = T&;
	using Pointer = T*;
	using Difference = std::ptrdiff_t;
	using Size = std::size_t;

public:
	using SpanStorage<T, N>::SpanStorage;
	constexpr Span(std::nullptr_t) : Span(nullptr, 0) {}

	template<typename C, typename = detail::ValidContainer<T, C>>
	constexpr Span(C& c) : Span(c.data(), c.size()) {}

	template<typename C, typename = detail::ValidContainer<T, C>, std::size_t S = C::size()>
	constexpr Span(C& c) : Span(c.data()) {}

	constexpr Pointer data() const noexcept { return this->data_; }
	constexpr Size size() const noexcept { return this->size_; }
	constexpr bool empty() const noexcept { return size() == 0; }

	constexpr Iterator begin() const noexcept { return data(); }
	constexpr Iterator end() const noexcept { return data() + size(); }

	constexpr ReverseIterator rbegin() const noexcept { return {end()}; }
	constexpr ReverseIterator rend() const noexcept { return {begin()}; }

	constexpr Reference operator[](Size i) const noexcept { return *(data() + i); }
	constexpr Reference at(Size i) const { checkThrow(i); return data()[i]; }

	constexpr Reference front() const noexcept { return *data(); }
	constexpr Reference back() const noexcept { return *(data() + size() - 1); }

	constexpr Span<T> slice(Size pos, Size size) const { return {data() + pos, size}; }
	template<Size S> constexpr Span<T, S> slice(Size pos) const { return {data() + pos}; }

protected:
	void checkThrow(Size i) const { if(i >= size()) throw std::out_of_range("nytl::Span::at"); }
};

// Default SpanStorage implementation for compile-time size
template<typename T, std::size_t N>
struct SpanStorage {
	constexpr SpanStorage() noexcept = default;
	constexpr SpanStorage(T* pointer, std::size_t size = N) : data_(pointer)
	{
		if(size != N) throw std::logic_error("nytl::Span:: invalid size");
		if(!pointer && size != 0) throw std::logic_error("nytl::Span:: invalid data");
	}
	constexpr SpanStorage(T& ref, std::size_t size = N) : SpanStorage(&ref, size) {}
	constexpr SpanStorage(T (&arr)[N]) : SpanStorage(arr, N) {}

	T* data_;
	constexpr static auto size_ = N;
};

// SpanStorage specialization for runtime size. Stored an extra size value.
template<typename T>
struct SpanStorage<T, constants::dynamicSize> {
	constexpr SpanStorage() noexcept = default;
	constexpr SpanStorage(T* pointer, std::size_t size) : data_(pointer), size_(size)
	{
		if(!pointer && size != 0) throw std::logic_error("nytl::Span:: invalid data");
	}
	constexpr SpanStorage(T& ref, std::size_t size) : SpanStorage(&ref, size) {}
	template<std::size_t S> constexpr SpanStorage(T (&arr)[S]) : SpanStorage(arr, S) {}

	T* data_;
	std::size_t size_;
};

namespace detail {

// Returns whether 'C' is a valid container to construct a Span<T> from
template<typename T, typename C>
struct ValidContainerT<T, C,
	typename std::enable_if<
		std::is_convertible<
			decltype(std::declval<C>().data()),
			T*
		>::value &&
		std::is_convertible<
			decltype(std::declval<C>().size()),
			std::size_t
		>::value
	>::type
> { using type = void; };

} // namespace nytl::detail

} // namespace nytl

#endif // header guard
<commit_msg>Update span.hpp<commit_after>// Copyright (c) 2017 nyorain
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt

///  file Contains the Span template class for not-owned contigous ranges.

#pragma once

#ifndef NYTL_INCLUDE_SPAN
#define NYTL_INCLUDE_SPAN

#include <nytl/fwd/span.hpp> // nytl::Span default template parameter
#include <nytl/scalar.hpp> // nytl::constants::dynamicSize

#include <cstdlib> // std::size_t
#include <stdexcept> // std::out_of_range
#include <array> // std::array

namespace nytl {
namespace detail {
	template<typename T, typename C, typename = void> struct ValidContainerT;
	template<typename T, typename C> using ValidContainer = typename ValidContainerT<T, C>::type;
} // namespace nytl::detail

/// The underlaying storage type of spans that is specialized for dyanmic size.
template<typename T, std::size_t N> struct SpanStorage;

/// \brief Describes a contigous, non-owned range of elements of type 'T'.
/// \details Spans can be used to pass sequences of elements around in a lightweight manner.
/// Its main use are function parameters sine instead of a std::vector it will not allocate
/// any memory or copy any elements but instead just reference them.
/// \tparam T The type the range is defined over. Use const types for non-mutable ranges.
/// \tparam N The size of the range. If not known at compile
/// time, use nytl::constants::dynamicSize (also defaulted to dynamicSize).
///
/// Some examples below. Note that Spans must be used carefully outside of temporary
/// expressions since they are only valid as long the object they reference is valid.
/// ```cpp
/// void foo(nytl::Span<std::string> names); // takes dyanmic amount of strings, might modify it
/// void bar(nytl::Span<const std::string, 3> names); // takes exactly 3 const strings
/// void baz(nytl::Span<const std::string, 5> names); // takes exactly 5 const strings
///
/// int main()
/// {
///		std::array<std::string, 3> namesArray {"foo", "bar", "baz"};
///		foo(namesArray); // works
/// 	bar(namesArray); // works
///		baz(namesArray); // will throw std::logic_error since baz requires exactly 5 strings
///
///		std::vector<std::string> namesVector {"foo", "bar", "baz", "abz", "bla"};
///		foo(namesVector); // works
///		bar(namesVector); // will throw std::logic_error since bar requires exactly 3 strings
///		baz(namesVector); // works
///
/// 	// If we only want the first 3 elements from namesVector as range we can do it like this
///		bar({namesVector.data(), 3}); // works, takes the first 3 elements
///		foo({*namesVector.data(), 4}); // we can also use references
///
///		// careful when using span outside of temporary expressions
///		auto span = nytl::Span<int>(std::vector<int>{4, 1, 2, 0});
/// 	// std::cout << span[0] << "\n"; // undefined behaviour!
/// }
///
/// void foo(nytl::Span<std::string> names)
/// {
///		// Some usage possibilities for span.
////	// The main usage is iterating over it:
///		for(auto& name : names)
///			std::cout << name << "\n";
///
///		// We might alternatively do this with a traditional for loop
///		for(auto i = 0u; i < names.size(); ++i)
///			std::cout << name << "\n";
///
///		// In this case we have a span of std::string, not const std::string,
///		// therefore we might also change it. This will change the names in the actual
///		// sequence this span references. Usually nytl::Span<const T> is used when the
///		// span is only read
///		if(!names.empty()) {
///			names.front() = "first name";
///			names.back() = "last name";
///		}
///
///		// A span can additionally be sliced into a subspan. This can either be
///		// done with a size known at compile time (which will result in a fixed-size span)
///		// or dynamically for a dynamic-sized span.
///		if(names.size() <= 2) return;
///		for(auto& name : names.slice(2, names.size() - 2)) // output everything but the first two
///			std::cout << name << "\n";
///
///		for(auto& name : names.slice<2>(0)) // output only the first two names
///			std::cout << name << "\n";
/// }
/// ```
template<typename T, std::size_t N>
class Span : public SpanStorage<T, N> {
public:
	using Value = T;
	using Iterator = T*;
	using ReverseIterator = std::reverse_iterator<T*>;
	using Reference = T&;
	using Pointer = T*;
	using Difference = std::ptrdiff_t;
	using Size = std::size_t;

public:
	using SpanStorage<T, N>::SpanStorage;
	constexpr Span(std::nullptr_t) : Span(nullptr, 0) {}

	template<typename C, typename = detail::ValidContainer<T, C>>
	constexpr Span(C& c) : Span(c.data(), c.size()) {}

	template<typename C, typename = detail::ValidContainer<T, C>, std::size_t S = C::size()>
	constexpr Span(C& c) : Span(c.data()) {}

	constexpr Pointer data() const noexcept { return this->data_; }
	constexpr Size size() const noexcept { return this->size_; }
	constexpr bool empty() const noexcept { return size() == 0; }

	constexpr Iterator begin() const noexcept { return data(); }
	constexpr Iterator end() const noexcept { return data() + size(); }

	constexpr ReverseIterator rbegin() const noexcept { return {end()}; }
	constexpr ReverseIterator rend() const noexcept { return {begin()}; }

	constexpr Reference operator[](Size i) const noexcept { return *(data() + i); }
	constexpr Reference at(Size i) const { checkThrow(i); return data()[i]; }

	constexpr Reference front() const noexcept { return *data(); }
	constexpr Reference back() const noexcept { return *(data() + size() - 1); }

	constexpr Span<T> slice(Size pos, Size size) const { return {data() + pos, size}; }
	template<Size S> constexpr Span<T, S> slice(Size pos) const { return {data() + pos}; }

protected:
	void checkThrow(Size i) const { if(i >= size()) throw std::out_of_range("nytl::Span::at"); }
};

// Default SpanStorage implementation for compile-time size
template<typename T, std::size_t N>
struct SpanStorage {
	constexpr SpanStorage() noexcept = default;
	constexpr SpanStorage(T* pointer, std::size_t size = N) : data_(pointer)
	{
		if(size != N) throw std::logic_error("nytl::Span:: invalid size");
		if(!pointer && size != 0) throw std::logic_error("nytl::Span:: invalid data");
	}
	constexpr SpanStorage(T& ref, std::size_t size = N) : SpanStorage(&ref, size) {}
	constexpr SpanStorage(T (&arr)[N]) : SpanStorage(arr, N) {}

	T* data_;
	constexpr static auto size_ = N;
};

// SpanStorage specialization for runtime size. Stored an extra size value.
template<typename T>
struct SpanStorage<T, constants::dynamicSize> {
	constexpr SpanStorage() noexcept = default;
	constexpr SpanStorage(T* pointer, std::size_t size) : data_(pointer), size_(size)
	{
		if(!pointer && size != 0) throw std::logic_error("nytl::Span:: invalid data");
	}
	constexpr SpanStorage(T& ref, std::size_t size) : SpanStorage(&ref, size) {}
	template<std::size_t S> constexpr SpanStorage(T (&arr)[S]) : SpanStorage(arr, S) {}

	T* data_;
	std::size_t size_;
};

namespace detail {

// Returns whether 'C' is a valid container to construct a Span<T> from
template<typename T, typename C>
struct ValidContainerT<T, C,
	typename std::enable_if<
		std::is_convertible<
			decltype(std::declval<C>().data()),
			T*
		>::value &&
		std::is_convertible<
			decltype(std::declval<C>().size()),
			std::size_t
		>::value
	>::type
> { using type = void; };

} // namespace detail
} // namespace nytl

#endif // header guard
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
#include "test/yuv_video_source.h"
#include "vp9/encoder/vp9_ratectrl.h"

namespace {

const unsigned int kFrames = 100;
const int kBitrate = 500;

#define ARF_NOT_SEEN               1000001
#define ARF_SEEN_ONCE              1000000

typedef struct {
  const char *filename;
  unsigned int width;
  unsigned int height;
  unsigned int framerate_num;
  unsigned int framerate_den;
  unsigned int input_bit_depth;
  vpx_img_fmt fmt;
  vpx_bit_depth_t bit_depth;
  unsigned int profile;
} TestVideoParam;

typedef struct {
  libvpx_test::TestMode mode;
  int cpu_used;
} TestEncodeParam;

const TestVideoParam kTestVectors[] = {
  // artificially increase framerate to trigger default check
  {"hantro_collage_w352h288.yuv", 352, 288, 5000, 1,
    8, VPX_IMG_FMT_I420, VPX_BITS_8, 0},
  {"hantro_collage_w352h288.yuv", 352, 288, 30, 1,
    8, VPX_IMG_FMT_I420, VPX_BITS_8, 0},
  {"rush_hour_444.y4m", 352, 288, 30, 1,
    8, VPX_IMG_FMT_I444, VPX_BITS_8, 1},
#if CONFIG_VP9_HIGHBITDEPTH
  // Add list of profile 2/3 test videos here ...
#endif  // CONFIG_VP9_HIGHBITDEPTH
};

const TestEncodeParam kEncodeVectors[] = {
  {::libvpx_test::kOnePassGood, 2},
  {::libvpx_test::kOnePassGood, 5},
  {::libvpx_test::kTwoPassGood, 1},
  {::libvpx_test::kTwoPassGood, 2},
  {::libvpx_test::kTwoPassGood, 5},
  {::libvpx_test::kRealTime, 5},
};

const int kMinArfVectors[] = {
  // NOTE: 0 refers to the default built-in logic in:
  //       vp9_rc_get_default_min_gf_interval(...)
  0, 4, 8, 12, 15
};

int is_extension_y4m(const char *filename) {
  const char *dot = strrchr(filename, '.');
  if (!dot || dot == filename)
    return 0;
  else
    return !strcmp(dot, ".y4m");
}

class ArfFreqTest
    : public ::libvpx_test::EncoderTest,
      public ::libvpx_test::CodecTestWith3Params<TestVideoParam, \
                                                 TestEncodeParam, int> {
 protected:
  ArfFreqTest()
      : EncoderTest(GET_PARAM(0)),
        test_video_param_(GET_PARAM(1)),
        test_encode_param_(GET_PARAM(2)),
        min_arf_requested_(GET_PARAM(3)) {
  }

  virtual ~ArfFreqTest() {}

  virtual void SetUp() {
    InitializeConfig();
    SetMode(test_encode_param_.mode);
    if (test_encode_param_.mode != ::libvpx_test::kRealTime) {
      cfg_.g_lag_in_frames = 25;
      cfg_.rc_end_usage = VPX_VBR;
    } else {
      cfg_.g_lag_in_frames = 0;
      cfg_.rc_end_usage = VPX_CBR;
      cfg_.rc_buf_sz = 1000;
      cfg_.rc_buf_initial_sz = 500;
      cfg_.rc_buf_optimal_sz = 600;
    }
    dec_cfg_.threads = 4;
  }

  virtual void BeginPassHook(unsigned int) {
    min_run_ = ARF_NOT_SEEN;
    run_of_visible_frames_ = 0;
  }

  int GetNumFramesInPkt(const vpx_codec_cx_pkt_t *pkt) {
    const uint8_t *buffer = reinterpret_cast<uint8_t*>(pkt->data.frame.buf);
    const uint8_t marker = buffer[pkt->data.frame.sz - 1];
    const int mag = ((marker >> 3) & 3) + 1;
    int frames = (marker & 0x7) + 1;
    const unsigned int index_sz = 2 + mag  * frames;
    // Check for superframe or not.
    // Assume superframe has only one visible frame, the rest being
    // invisible. If superframe index is not found, then there is only
    // one frame.
    if (!((marker & 0xe0) == 0xc0 &&
          pkt->data.frame.sz >= index_sz &&
          buffer[pkt->data.frame.sz - index_sz] == marker)) {
      frames = 1;
    }
    return frames;
  }

  virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
    if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
      return;
    const int frames = GetNumFramesInPkt(pkt);
    if (frames == 1) {
      run_of_visible_frames_++;
    } else if (frames == 2) {
      if (min_run_ == ARF_NOT_SEEN) {
        min_run_ = ARF_SEEN_ONCE;
      } else if (min_run_ == ARF_SEEN_ONCE ||
                 run_of_visible_frames_ < min_run_) {
        min_run_ = run_of_visible_frames_;
      }
      run_of_visible_frames_ = 1;
    } else {
      min_run_ = 0;
      run_of_visible_frames_ = 1;
    }
  }

  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
                                  ::libvpx_test::Encoder *encoder) {
    if (video->frame() == 0) {
      encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
      encoder->Control(VP9E_SET_TILE_COLUMNS, 4);
      encoder->Control(VP8E_SET_CPUUSED, test_encode_param_.cpu_used);
      encoder->Control(VP9E_SET_MIN_GF_INTERVAL, min_arf_requested_);
      if (test_encode_param_.mode != ::libvpx_test::kRealTime) {
        encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
        encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
        encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
        encoder->Control(VP8E_SET_ARNR_TYPE, 3);
      }
    }
  }

  int GetMinVisibleRun() const {
    return min_run_;
  }

  int GetMinArfDistanceRequested() const {
    if (min_arf_requested_)
      return min_arf_requested_;
    else
      return vp9_rc_get_default_min_gf_interval(
          test_video_param_.width, test_video_param_.height,
          (double)test_video_param_.framerate_num /
          test_video_param_.framerate_den);
  }

  TestVideoParam test_video_param_;
  TestEncodeParam test_encode_param_;

 private:
  int min_arf_requested_;
  int min_run_;
  int run_of_visible_frames_;
};

TEST_P(ArfFreqTest, MinArfFreqTest) {
  cfg_.rc_target_bitrate = kBitrate;
  cfg_.g_error_resilient = 0;
  cfg_.g_profile = test_video_param_.profile;
  cfg_.g_input_bit_depth = test_video_param_.input_bit_depth;
  cfg_.g_bit_depth = test_video_param_.bit_depth;
  init_flags_ = VPX_CODEC_USE_PSNR;
  if (cfg_.g_bit_depth > 8)
    init_flags_ |= VPX_CODEC_USE_HIGHBITDEPTH;

  libvpx_test::VideoSource *video;
  if (is_extension_y4m(test_video_param_.filename)) {
    video = new libvpx_test::Y4mVideoSource(test_video_param_.filename,
                                            0, kFrames);
  } else {
    video = new libvpx_test::YUVVideoSource(test_video_param_.filename,
                                            test_video_param_.fmt,
                                            test_video_param_.width,
                                            test_video_param_.height,
                                            test_video_param_.framerate_num,
                                            test_video_param_.framerate_den,
                                            0, kFrames);
  }

  ASSERT_NO_FATAL_FAILURE(RunLoop(video));
  const int min_run = GetMinVisibleRun();
  const int min_arf_dist_requested = GetMinArfDistanceRequested();
  if (min_run != ARF_NOT_SEEN && min_run != ARF_SEEN_ONCE) {
    const int min_arf_dist = min_run + 1;
    EXPECT_GE(min_arf_dist, min_arf_dist_requested);
  }
  delete(video);
}

VP9_INSTANTIATE_TEST_CASE(
    ArfFreqTest,
    ::testing::ValuesIn(kTestVectors),
    ::testing::ValuesIn(kEncodeVectors),
    ::testing::ValuesIn(kMinArfVectors));

VP10_INSTANTIATE_TEST_CASE(
    ArfFreqTest,
    ::testing::ValuesIn(kTestVectors),
    ::testing::ValuesIn(kEncodeVectors),
    ::testing::ValuesIn(kMinArfVectors));
}  // namespace
<commit_msg>vp9_arf_freq_test: disable vp10 w/high bitdepth<commit_after>/*
 *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
#include "test/yuv_video_source.h"
#include "vp9/encoder/vp9_ratectrl.h"

namespace {

const unsigned int kFrames = 100;
const int kBitrate = 500;

#define ARF_NOT_SEEN               1000001
#define ARF_SEEN_ONCE              1000000

typedef struct {
  const char *filename;
  unsigned int width;
  unsigned int height;
  unsigned int framerate_num;
  unsigned int framerate_den;
  unsigned int input_bit_depth;
  vpx_img_fmt fmt;
  vpx_bit_depth_t bit_depth;
  unsigned int profile;
} TestVideoParam;

typedef struct {
  libvpx_test::TestMode mode;
  int cpu_used;
} TestEncodeParam;

const TestVideoParam kTestVectors[] = {
  // artificially increase framerate to trigger default check
  {"hantro_collage_w352h288.yuv", 352, 288, 5000, 1,
    8, VPX_IMG_FMT_I420, VPX_BITS_8, 0},
  {"hantro_collage_w352h288.yuv", 352, 288, 30, 1,
    8, VPX_IMG_FMT_I420, VPX_BITS_8, 0},
  {"rush_hour_444.y4m", 352, 288, 30, 1,
    8, VPX_IMG_FMT_I444, VPX_BITS_8, 1},
#if CONFIG_VP9_HIGHBITDEPTH
  // Add list of profile 2/3 test videos here ...
#endif  // CONFIG_VP9_HIGHBITDEPTH
};

const TestEncodeParam kEncodeVectors[] = {
  {::libvpx_test::kOnePassGood, 2},
  {::libvpx_test::kOnePassGood, 5},
  {::libvpx_test::kTwoPassGood, 1},
  {::libvpx_test::kTwoPassGood, 2},
  {::libvpx_test::kTwoPassGood, 5},
  {::libvpx_test::kRealTime, 5},
};

const int kMinArfVectors[] = {
  // NOTE: 0 refers to the default built-in logic in:
  //       vp9_rc_get_default_min_gf_interval(...)
  0, 4, 8, 12, 15
};

int is_extension_y4m(const char *filename) {
  const char *dot = strrchr(filename, '.');
  if (!dot || dot == filename)
    return 0;
  else
    return !strcmp(dot, ".y4m");
}

class ArfFreqTest
    : public ::libvpx_test::EncoderTest,
      public ::libvpx_test::CodecTestWith3Params<TestVideoParam, \
                                                 TestEncodeParam, int> {
 protected:
  ArfFreqTest()
      : EncoderTest(GET_PARAM(0)),
        test_video_param_(GET_PARAM(1)),
        test_encode_param_(GET_PARAM(2)),
        min_arf_requested_(GET_PARAM(3)) {
  }

  virtual ~ArfFreqTest() {}

  virtual void SetUp() {
    InitializeConfig();
    SetMode(test_encode_param_.mode);
    if (test_encode_param_.mode != ::libvpx_test::kRealTime) {
      cfg_.g_lag_in_frames = 25;
      cfg_.rc_end_usage = VPX_VBR;
    } else {
      cfg_.g_lag_in_frames = 0;
      cfg_.rc_end_usage = VPX_CBR;
      cfg_.rc_buf_sz = 1000;
      cfg_.rc_buf_initial_sz = 500;
      cfg_.rc_buf_optimal_sz = 600;
    }
    dec_cfg_.threads = 4;
  }

  virtual void BeginPassHook(unsigned int) {
    min_run_ = ARF_NOT_SEEN;
    run_of_visible_frames_ = 0;
  }

  int GetNumFramesInPkt(const vpx_codec_cx_pkt_t *pkt) {
    const uint8_t *buffer = reinterpret_cast<uint8_t*>(pkt->data.frame.buf);
    const uint8_t marker = buffer[pkt->data.frame.sz - 1];
    const int mag = ((marker >> 3) & 3) + 1;
    int frames = (marker & 0x7) + 1;
    const unsigned int index_sz = 2 + mag  * frames;
    // Check for superframe or not.
    // Assume superframe has only one visible frame, the rest being
    // invisible. If superframe index is not found, then there is only
    // one frame.
    if (!((marker & 0xe0) == 0xc0 &&
          pkt->data.frame.sz >= index_sz &&
          buffer[pkt->data.frame.sz - index_sz] == marker)) {
      frames = 1;
    }
    return frames;
  }

  virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
    if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
      return;
    const int frames = GetNumFramesInPkt(pkt);
    if (frames == 1) {
      run_of_visible_frames_++;
    } else if (frames == 2) {
      if (min_run_ == ARF_NOT_SEEN) {
        min_run_ = ARF_SEEN_ONCE;
      } else if (min_run_ == ARF_SEEN_ONCE ||
                 run_of_visible_frames_ < min_run_) {
        min_run_ = run_of_visible_frames_;
      }
      run_of_visible_frames_ = 1;
    } else {
      min_run_ = 0;
      run_of_visible_frames_ = 1;
    }
  }

  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
                                  ::libvpx_test::Encoder *encoder) {
    if (video->frame() == 0) {
      encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
      encoder->Control(VP9E_SET_TILE_COLUMNS, 4);
      encoder->Control(VP8E_SET_CPUUSED, test_encode_param_.cpu_used);
      encoder->Control(VP9E_SET_MIN_GF_INTERVAL, min_arf_requested_);
      if (test_encode_param_.mode != ::libvpx_test::kRealTime) {
        encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
        encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
        encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
        encoder->Control(VP8E_SET_ARNR_TYPE, 3);
      }
    }
  }

  int GetMinVisibleRun() const {
    return min_run_;
  }

  int GetMinArfDistanceRequested() const {
    if (min_arf_requested_)
      return min_arf_requested_;
    else
      return vp9_rc_get_default_min_gf_interval(
          test_video_param_.width, test_video_param_.height,
          (double)test_video_param_.framerate_num /
          test_video_param_.framerate_den);
  }

  TestVideoParam test_video_param_;
  TestEncodeParam test_encode_param_;

 private:
  int min_arf_requested_;
  int min_run_;
  int run_of_visible_frames_;
};

TEST_P(ArfFreqTest, MinArfFreqTest) {
  cfg_.rc_target_bitrate = kBitrate;
  cfg_.g_error_resilient = 0;
  cfg_.g_profile = test_video_param_.profile;
  cfg_.g_input_bit_depth = test_video_param_.input_bit_depth;
  cfg_.g_bit_depth = test_video_param_.bit_depth;
  init_flags_ = VPX_CODEC_USE_PSNR;
  if (cfg_.g_bit_depth > 8)
    init_flags_ |= VPX_CODEC_USE_HIGHBITDEPTH;

  libvpx_test::VideoSource *video;
  if (is_extension_y4m(test_video_param_.filename)) {
    video = new libvpx_test::Y4mVideoSource(test_video_param_.filename,
                                            0, kFrames);
  } else {
    video = new libvpx_test::YUVVideoSource(test_video_param_.filename,
                                            test_video_param_.fmt,
                                            test_video_param_.width,
                                            test_video_param_.height,
                                            test_video_param_.framerate_num,
                                            test_video_param_.framerate_den,
                                            0, kFrames);
  }

  ASSERT_NO_FATAL_FAILURE(RunLoop(video));
  const int min_run = GetMinVisibleRun();
  const int min_arf_dist_requested = GetMinArfDistanceRequested();
  if (min_run != ARF_NOT_SEEN && min_run != ARF_SEEN_ONCE) {
    const int min_arf_dist = min_run + 1;
    EXPECT_GE(min_arf_dist, min_arf_dist_requested);
  }
  delete(video);
}

VP9_INSTANTIATE_TEST_CASE(
    ArfFreqTest,
    ::testing::ValuesIn(kTestVectors),
    ::testing::ValuesIn(kEncodeVectors),
    ::testing::ValuesIn(kMinArfVectors));

#if CONFIG_VP9_HIGHBITDEPTH
# if CONFIG_VP10_ENCODER
// TODO(angiebird): 25-29 fail in high bitdepth mode.
INSTANTIATE_TEST_CASE_P(
    DISABLED_VP10, ArfFreqTest,
    ::testing::Combine(
        ::testing::Values(static_cast<const libvpx_test::CodecFactory *>(
            &libvpx_test::kVP10)),
        ::testing::ValuesIn(kTestVectors),
        ::testing::ValuesIn(kEncodeVectors),
        ::testing::ValuesIn(kMinArfVectors)));
# endif  // CONFIG_VP10_ENCODER
#else
VP10_INSTANTIATE_TEST_CASE(
    ArfFreqTest,
    ::testing::ValuesIn(kTestVectors),
    ::testing::ValuesIn(kEncodeVectors),
    ::testing::ValuesIn(kMinArfVectors));
#endif  // CONFIG_VP9_HIGHBITDEPTH
}  // namespace
<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE
#include <boost/test/included/unit_test.hpp>

#include "test_servers.hpp"

BOOST_AUTO_TEST_SUITE( write_errors )

BOOST_FIXTURE_TEST_CASE( pdu_to_small, test::small_temperature_service_with_response<> )
{
    BOOST_CHECK( check_error_response( { 0x12, 0x02 }, 0x12, 0x0000, 0x04 ) );
}

BOOST_FIXTURE_TEST_CASE( no_such_handle, test::small_temperature_service_with_response<> )
{
    BOOST_CHECK( check_error_response( { 0x12, 0x17, 0xAA, 0x01 }, 0x12, 0xAA17, 0x0A ) );
    BOOST_CHECK( check_error_response( { 0x12, 0x04, 0x00       }, 0x12, 0x0004, 0x0A ) );
}

BOOST_FIXTURE_TEST_CASE( invalid_handle, test::small_temperature_service_with_response<> )
{
    BOOST_CHECK( check_error_response( { 0x12, 0x00, 0x00 }, 0x12, 0x0000, 0x01 ) );
}

BOOST_FIXTURE_TEST_CASE( write_protected, test::small_temperature_service_with_response<> )
{
    BOOST_CHECK( check_error_response( { 0x12, 0x03, 0x00, 0x00, 0x00 }, 0x12, 0x0003, 0x03 ) );
}

std::uint32_t value = 0x0000;

typedef bluetoe::server<
    bluetoe::service<
        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,
        bluetoe::characteristic<
            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,
            bluetoe::bind_characteristic_value< decltype( value ), &value >
        >
    >
> small_value_server;

BOOST_FIXTURE_TEST_CASE( pdu_to_large, test::request_with_reponse< small_value_server > )
{
    value = 0x3512;
    BOOST_CHECK( check_error_response( { 0x12, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }, 0x12, 0x0003, 0x0D ) );
    BOOST_CHECK_EQUAL( value, 0x3512u );
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE( write_requests )

std::uint32_t value = 0x0000;

typedef bluetoe::server<
    bluetoe::service<
        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,
        bluetoe::characteristic<
            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,
            bluetoe::bind_characteristic_value< decltype( value ), &value >
        >
    >
> small_value_server;

BOOST_FIXTURE_TEST_CASE( write_full_data, test::request_with_reponse< small_value_server > )
{
    value = 0x3512;
    l2cap_input( { 0x12, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04 } );
    expected_result( { 0x13 } );
    BOOST_CHECK_EQUAL( value, 0x04030201u );
}

BOOST_FIXTURE_TEST_CASE( write_full_data_part, test::request_with_reponse< small_value_server > )
{
    value = 0x44332211;
    l2cap_input( { 0x12, 0x03, 0x00, 0x01, 0x02, 0x03 } );
    expected_result( { 0x13 } );
    BOOST_CHECK_EQUAL( value, 0x44030201u );
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>add test for write request / command<commit_after>#define BOOST_TEST_MODULE
#include <boost/test/included/unit_test.hpp>

#include "test_servers.hpp"

BOOST_AUTO_TEST_SUITE( write_errors )

BOOST_FIXTURE_TEST_CASE( pdu_to_small, test::small_temperature_service_with_response<> )
{
    BOOST_CHECK( check_error_response( { 0x12, 0x02 }, 0x12, 0x0000, 0x04 ) );
}

BOOST_FIXTURE_TEST_CASE( no_such_handle, test::small_temperature_service_with_response<> )
{
    BOOST_CHECK( check_error_response( { 0x12, 0x17, 0xAA, 0x01 }, 0x12, 0xAA17, 0x0A ) );
    BOOST_CHECK( check_error_response( { 0x12, 0x04, 0x00       }, 0x12, 0x0004, 0x0A ) );
}

BOOST_FIXTURE_TEST_CASE( invalid_handle, test::small_temperature_service_with_response<> )
{
    BOOST_CHECK( check_error_response( { 0x12, 0x00, 0x00 }, 0x12, 0x0000, 0x01 ) );
}

BOOST_FIXTURE_TEST_CASE( write_protected, test::small_temperature_service_with_response<> )
{
    BOOST_CHECK( check_error_response( { 0x12, 0x03, 0x00, 0x00, 0x00 }, 0x12, 0x0003, 0x03 ) );
}

std::uint32_t value = 0x0000;

typedef bluetoe::server<
    bluetoe::service<
        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,
        bluetoe::characteristic<
            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,
            bluetoe::bind_characteristic_value< decltype( value ), &value >
        >
    >
> small_value_server;

BOOST_FIXTURE_TEST_CASE( pdu_to_large, test::request_with_reponse< small_value_server > )
{
    value = 0x3512;
    BOOST_CHECK( check_error_response( { 0x12, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }, 0x12, 0x0003, 0x0D ) );
    BOOST_CHECK_EQUAL( value, 0x3512u );
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE( write_requests )

std::uint32_t value = 0x0000;

typedef bluetoe::server<
    bluetoe::service<
        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,
        bluetoe::characteristic<
            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,
            bluetoe::bind_characteristic_value< decltype( value ), &value >
        >
    >
> small_value_server;

BOOST_FIXTURE_TEST_CASE( write_full_data, test::request_with_reponse< small_value_server > )
{
    value = 0x3512;
    l2cap_input( { 0x12, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04 } );
    expected_result( { 0x13 } );
    BOOST_CHECK_EQUAL( value, 0x04030201u );
}

BOOST_FIXTURE_TEST_CASE( write_full_data_part, test::request_with_reponse< small_value_server > )
{
    value = 0x44332211;
    l2cap_input( { 0x12, 0x03, 0x00, 0x01, 0x02, 0x03 } );
    expected_result( { 0x13 } );
    BOOST_CHECK_EQUAL( value, 0x44030201u );
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE( write_requests_with_fixed_handles )

std::uint32_t value = 0x0000;

typedef bluetoe::server<
    bluetoe::service<
        bluetoe::attribute_handle< 0x4444 >,
        bluetoe::service_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CA9 >,
        bluetoe::characteristic<
            bluetoe::characteristic_uuid< 0x8C8B4094, 0x0DE2, 0x499F, 0xA28A, 0x4EED5BC73CAA >,
            bluetoe::bind_characteristic_value< decltype( value ), &value >
        >
    >
> small_value_server;

BOOST_FIXTURE_TEST_CASE( write_full_data, test::request_with_reponse< small_value_server > )
{
    value = 0x3512;
    l2cap_input( { 0x12, 0x46, 0x44, 0x01, 0x02, 0x03, 0x04 } );
    expected_result( { 0x13 } );
    BOOST_CHECK_EQUAL( value, 0x04030201u );
}

BOOST_FIXTURE_TEST_CASE( write_full_data_part, test::request_with_reponse< small_value_server > )
{
    value = 0x44332211;
    l2cap_input( { 0x12, 0x46, 0x44, 0x01, 0x02, 0x03 } );
    expected_result( { 0x13 } );
    BOOST_CHECK_EQUAL( value, 0x44030201u );
}

BOOST_AUTO_TEST_SUITE_END()
<|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 QtCore 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 "qservicemanager.h"
#include "qserviceplugininterface.h"
#include "qabstractsecuritysession.h"
#include "servicedatabase.h"

#include <QObject>
#include <QPluginLoader>
#include <QBuffer>
#include <QFile>
#include <QDebug>

QT_BEGIN_NAMESPACE

static QString qservicemanager_resolveLibraryPath(const QString &libNameOrPath)
{
    if (QFile::exists(libNameOrPath))
        return libNameOrPath;

    // try to find plug-in via QLibrary
    const QStringList paths = QCoreApplication::libraryPaths();
    for (int i=0; i<paths.count(); i++) {
        QLibrary lib(paths[i] + QDir::separator() + libNameOrPath);
        if (lib.load()) {
            lib.unload();
            return lib.fileName();
        }
    }
    return QString();
}

class QServicePluginCleanup : public QObject
{
    Q_OBJECT
public:
    QServicePluginCleanup(QPluginLoader *loader, QServicePluginInterface *pluginInterface, QObject *parent = 0)
        : QObject(parent),
          m_pluginInterface(pluginInterface),
          m_loader(loader)
    {
    }

    ~QServicePluginCleanup()
    {
        delete m_pluginInterface;
        if (m_loader) {
            m_loader->unload();
            delete m_loader;
        }
    }

    QServicePluginInterface *m_pluginInterface;
    QPluginLoader *m_loader;
};

class QServiceManagerPrivate
{
public:
    ServiceDatabase *database;
    QServiceManager::Scope scope;

    void init(QServiceManager *mgr, QServiceManager::Scope databaseScope)
    {
        database = new ServiceDatabase;
        scope = databaseScope;

        QObject::connect(database, SIGNAL(serviceAdded(QString)),
                mgr, SIGNAL(serviceAdded(QString)));
        QObject::connect(database, SIGNAL(serviceRemoved(QString)),
                mgr, SIGNAL(serviceRemoved(QString)));

        if (!database->open())
            qWarning("QServiceManager: unable to open services database");
    }
};

/*!
    \class QServiceManager
    \brief The QServiceManager class enables the loading of service plugins
    and the (de)registration of services.

    A service is a stand-alone component that can be used by multiple clients.
    Each service implementation must derive from QObject. Clients request a
    reference to a service via \l loadInterface() or \l getInterface().

    Services are separate deliveries in the form of plug-ins. New services can be (de)registered
    at any time via \l addService() and \l removeService() respectively. Such an event is
    published via the \l serviceAdded() and \l serviceRemoved() signal.
    Each service plug-in must implement QServicePluginInterface.

    Each plug-in may support multiple interfaces and may even provide multiple implementations
    for the same interface. Individual implementations are identified via
    QServiceInterfaceDescriptor. For a more detailed explanation of services and how they relate to
    interface and their implementations please see QServiceInterfaceDescriptor.

    \sa QServicePluginInterface, QServiceContext, QAbstractSecuritySession
*/

/*!
    \enum QServiceManager::Scope

    \value UserScope When adding and removing services, use a database
    specific to the current user (e.g. in the user's home directory). When
    searching for services and interface implementations, first search in the
    user-specific database; if the service or interface implementation
    is not found, search in the system-wide services database.

    \value SystemScope When adding and removing services, use a database
    in a global location accessible by all users. When searching
    for services and interface implementations, search only in the system-wide
    services database.
*/

/*!
    \fn void QServiceManager::serviceAdded(const QString& serviceName)

    This signal is emited whenever a new service with the given
    \a serviceName has been registered with the service manager.

    \sa addService()
*/

/*!
    \fn void QServiceManager::serviceRemoved(const QString& serviceName)

    This signal is emited whenever a service with the given
    \a serviceName has been deregistered with the service manager.

    \sa removeService()
*/

/*!
    Creates a service manager with the given \a parent.

    The scope will default to QServiceManager::UserScope.
*/
QServiceManager::QServiceManager(QObject *parent)
    : QObject(parent),
      d(new QServiceManagerPrivate)
{
    d->init(this, UserScope);
}

/*!
    Creates a service manager with the given \a scope and \a parent.
*/
QServiceManager::QServiceManager(Scope scope, QObject *parent)
    : QObject(parent),
      d(new QServiceManagerPrivate)
{
    d->init(this, scope);
}

/*!
    Destroys the service manager.
*/
QServiceManager::~QServiceManager()
{
    d->database->close();
    delete d->database;
    delete d;
}

/*!
    Returns the scope used for registering and searching of services.
*/
QServiceManager::Scope QServiceManager::scope() const
{
    return d->scope;
}

/*!
    Returns a list of the services that provide the interface specified by
    \a interfaceName.
*/
QStringList QServiceManager::findServices(const QString& interfaceName) const
{
    QStringList services;
    QList<ServiceInfo> serviceInfoList;
    if (!d->database->isOpen())
        return services;
    services = d->database->getServiceNames(interfaceName);
    return services;
}

/*!
    Returns a list of the interfaces that match the specified \a filter.
*/
QList<QServiceInterfaceDescriptor> QServiceManager::findInterfaces(const QServiceFilter& filter) const
{
    if (!d->database->isOpen())
        return QList<QServiceInterfaceDescriptor>();
    bool ok = false;
    QList<QServiceInterfaceDescriptor> descriptors = d->database->getInterfaces(filter, &ok);
    if (!ok)
        return QList<QServiceInterfaceDescriptor>();
    return descriptors;
}

/*!
    Returns a list of the interfaces provided by the service named
    \a serviceName.
*/
QList<QServiceInterfaceDescriptor> QServiceManager::findInterfaces(const QString& serviceName) const
{
    QServiceFilter filter;
    if (!serviceName.isEmpty())
        filter.setServiceName(serviceName);
    return findInterfaces(filter);
}

/*!
    Loads and returns the interface specified by \a interfaceName, as
    provided by the default service for this interface, using the given
    \a context and \a session. \a context and \a session object are owned
    by the caller of this function.

    The caller takes ownership of the returned pointer.

    This function returns a null pointer if the requested service cannot be found.
*/
QObject* QServiceManager::loadInterface(const QString& interfaceName, QServiceContext* context, QAbstractSecuritySession* session)
{
    return loadInterface(defaultServiceInterface(interfaceName), context, session);
}

/*!
    Loads and returns the interface specified by \a descriptor using the
    given \a context and \a session. \a context and \a session object are owned
    by the caller of this function.

    The caller takes ownership of the returned pointer.

    This function returns a null pointer if the requested service cannot be found.
*/
QObject* QServiceManager::loadInterface(const QServiceInterfaceDescriptor& descriptor, QServiceContext* context, QAbstractSecuritySession* session)
{
    if (!descriptor.isValid()) {
        qWarning() << "QServiceManager::loadInterface() given invalid descriptor";
        return 0;
    }

    const QStringList serviceCaps = descriptor.property(QServiceInterfaceDescriptor::Capabilities).toStringList();
    if ( session && !session->isAllowed(serviceCaps) )
        return 0;  //TODO set error state on context object, if it exists

    QString serviceFilePath = qservicemanager_resolveLibraryPath(
            descriptor.property(QServiceInterfaceDescriptor::Location).toString());
    if (serviceFilePath.isEmpty()) {
        qWarning() << "QServiceManager::loadInterface() cannot locate library file for plugin:"
                << descriptor.property(QServiceInterfaceDescriptor::Location).toString();
        return 0;
    }

    QPluginLoader *loader = new QPluginLoader(serviceFilePath);
    QServicePluginInterface *pluginIFace = qobject_cast<QServicePluginInterface *>(loader->instance());

    if (pluginIFace) {
        QObject *obj = pluginIFace->createInstance(descriptor, context, session);
        if (obj) {
            QServicePluginCleanup *cleanup = new QServicePluginCleanup(loader, pluginIFace);
            QObject::connect(obj, SIGNAL(destroyed()), cleanup, SLOT(deleteLater()));
            return obj;
        }
        delete pluginIFace;
    }

    qWarning() << "QServiceManager::loadInterface() cannot load plugin at"
            << serviceFilePath << ":" << loader->errorString();
    loader->unload();
    delete loader;

    return 0;
}

/*!
    \fn T* QServiceManager::getInterface(const QString& interfaceName, QServiceContext* context, QAbstractSecuritySession* session)

    Loads the service object implementing \a interfaceName,
    as provided by the default service for this interface, using the given
    \a context and \a session. \a context and \a session object are owned
    by the caller of this function. The template class must be derived from QObject.

    If \a interfaceName is not a known interface the returned pointer will be null.

    The caller takes ownership of the returned pointer.
*/

/*!
    \fn T* QServiceManager::getInterface(const QServiceInterfaceDescriptor& serviceDescriptor, QServiceContext* context, QAbstractSecuritySession* session)

    Loads the service object identified by \a serviceDescriptor
    using the given \a context and \a session. \a context and \a session object are owned
    by the caller of this function. The template class must be derived from QObject.

    If the \a serviceDescriptor is not valid the returned pointer will be null.

    The caller takes ownership of the returned pointer.
*/

/*!
    Registers the service defined by the XML file at \a xmlFilePath.
    Returns true if the registration succeeded, and false otherwise.

    If a previously unkown interface is added the newly registered service automatically
    becomes the new default service provider for the new interface.

    A service plugin cannot be added if another service is already registered
    with the same plugin file path.  A service plugin also cannot be added if
    the service is already registered and implements any of the same interface
    versions that the new plugin implements.

    \sa setDefaultServiceForInterface()
*/
bool QServiceManager::addService(const QString& xmlFilePath)
{
    QFile *f = new QFile(xmlFilePath);
    bool b = addService(f);
    delete f;
    return b;
}

/*!
    Registers the service defined by the XML data from the given \a device.
    Returns true if the registration succeeded, and false otherwise. If a
    previously unkown interface is added the newly registered service
    automatically becomes the new default service provider for the new
    interface.

    Registering a service also causes QServicePluginInterface::installService()
    to be called on the service. If the service plugin is not accessible
    (e.g. if the plugin file is not found) and \c installService() cannot
    be invoked on the service, the registration fails and this method returns
    false.

    A service plugin cannot be added if another service is already registered
    with the same plugin file path.  A service plugin also cannot be added if
    the service is already registered and implements any of the same interface
    versions that the new plugin implements.

    \sa setDefaultServiceForInterface()
*/
bool QServiceManager::addService(QIODevice *device)
{
    if (!d->database->isOpen())
        return false;
    ServiceMetaData data(device);
    if (!data.extractMetadata())
        return false;

    bool result = d->database->registerService(data);
    if (result) {
        QPluginLoader *loader = new QPluginLoader(qservicemanager_resolveLibraryPath(data.location()));
        QServicePluginInterface *pluginIFace = qobject_cast<QServicePluginInterface *>(loader->instance());
        if (pluginIFace) {
            pluginIFace->installService();
        } else {
            result = false;
            d->database->unregisterService(data.name());
        }
        loader->unload();
        delete loader;
    }
    return result;
}

/*!
    Unregisters the service specified by \a serviceName.

    Returns true if the unregistration succeeded, and false otherwise.

    If a default service implementation is removed and there are other implementations
    for the same interface, the service manager chooses the implementation with the
    highest version number as the new default.  If there is more than one serivce
    with the same version number, the service manager makes a random choice with
    regards to the new default implementation. If this is
    not the desired behaviour the default selection should be updated
    via setDefaultServiceForInterface().
*/
bool QServiceManager::removeService(const QString& serviceName)
{
    if (!d->database->isOpen())
        return false;
    if (serviceName.isEmpty())
        return false;

    // Call QServicePluginInterface::uninstallService() on all plugins that
    // match this service

    QSet<QString> pluginPathsSet;
    QList<QServiceInterfaceDescriptor> descriptors = findInterfaces(serviceName);
    for (int i=0; i<descriptors.count(); i++)
        pluginPathsSet << descriptors[i].property(QServiceInterfaceDescriptor::Location).toString();

    QList<QString> pluginPaths = pluginPathsSet.toList();
    for (int i=0; i<pluginPaths.count(); i++) {
        QPluginLoader *loader = new QPluginLoader(qservicemanager_resolveLibraryPath(pluginPaths[i]));
        QServicePluginInterface *pluginIFace = qobject_cast<QServicePluginInterface *>(loader->instance());
        if (pluginIFace)
            pluginIFace->uninstallService();
        else
            qWarning() << "QServiceManager: unable to invoke uninstallService() on removed service";
        loader->unload();
        delete loader;
    }

    return d->database->unregisterService(serviceName);
}

/*!
    Sets the default interface implementation for \a interfaceName to the
    matching interface implementation provided by \a service.

    If \a service provides more than one interface implementation for
    \a interfaceName, the newest version of the interface is set as the
    default.

    Returns true if the operation succeeded, and false otherwise.
*/
bool QServiceManager::setDefaultServiceForInterface(const QString &service, const QString &interfaceName)
{
    if (!d->database->isOpen())
        return false;
    if (interfaceName.isEmpty() || service.isEmpty())
        return false;
    return d->database->setDefaultService(service, interfaceName);
}

/*!
    \overload

    Sets the interface implementation specified by \a descriptor to be the
    default implementation for the particular interface specified in the
    descriptor.

    Returns true if the operation succeeded, and false otherwise.
*/
bool QServiceManager::setDefaultServiceForInterface(const QServiceInterfaceDescriptor& descriptor)
{
    if (!d->database->isOpen())
        return false;
    if (!descriptor.isValid())
        return false;
    return d->database->setDefaultService(descriptor);
}

/*!
    Returns the default interface for the given \a interfaceName.
*/
QServiceInterfaceDescriptor QServiceManager::defaultServiceInterface(const QString& interfaceName) const
{
    if (!d->database->isOpen())
        return QServiceInterfaceDescriptor();
    bool ok = false;
    QServiceInterfaceDescriptor info;
    info = d->database->defaultServiceInterface(interfaceName, &ok);
    if (!ok)
        return QServiceInterfaceDescriptor();

    return info;
}

QT_END_NAMESPACE

#include "qservicemanager.moc"
<commit_msg>Don't mention databases for UserScope/SystemScope 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 QtCore 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 "qservicemanager.h"
#include "qserviceplugininterface.h"
#include "qabstractsecuritysession.h"
#include "servicedatabase.h"

#include <QObject>
#include <QPluginLoader>
#include <QBuffer>
#include <QFile>
#include <QDebug>

QT_BEGIN_NAMESPACE

static QString qservicemanager_resolveLibraryPath(const QString &libNameOrPath)
{
    if (QFile::exists(libNameOrPath))
        return libNameOrPath;

    // try to find plug-in via QLibrary
    const QStringList paths = QCoreApplication::libraryPaths();
    for (int i=0; i<paths.count(); i++) {
        QLibrary lib(paths[i] + QDir::separator() + libNameOrPath);
        if (lib.load()) {
            lib.unload();
            return lib.fileName();
        }
    }
    return QString();
}

class QServicePluginCleanup : public QObject
{
    Q_OBJECT
public:
    QServicePluginCleanup(QPluginLoader *loader, QServicePluginInterface *pluginInterface, QObject *parent = 0)
        : QObject(parent),
          m_pluginInterface(pluginInterface),
          m_loader(loader)
    {
    }

    ~QServicePluginCleanup()
    {
        delete m_pluginInterface;
        if (m_loader) {
            m_loader->unload();
            delete m_loader;
        }
    }

    QServicePluginInterface *m_pluginInterface;
    QPluginLoader *m_loader;
};

class QServiceManagerPrivate
{
public:
    ServiceDatabase *database;
    QServiceManager::Scope scope;

    void init(QServiceManager *mgr, QServiceManager::Scope databaseScope)
    {
        database = new ServiceDatabase;
        scope = databaseScope;

        QObject::connect(database, SIGNAL(serviceAdded(QString)),
                mgr, SIGNAL(serviceAdded(QString)));
        QObject::connect(database, SIGNAL(serviceRemoved(QString)),
                mgr, SIGNAL(serviceRemoved(QString)));

        if (!database->open())
            qWarning("QServiceManager: unable to open services database");
    }
};

/*!
    \class QServiceManager
    \brief The QServiceManager class enables the loading of service plugins
    and the (de)registration of services.

    A service is a stand-alone component that can be used by multiple clients.
    Each service implementation must derive from QObject. Clients request a
    reference to a service via \l loadInterface() or \l getInterface().

    Services are separate deliveries in the form of plug-ins. New services can be (de)registered
    at any time via \l addService() and \l removeService() respectively. Such an event is
    published via the \l serviceAdded() and \l serviceRemoved() signal.
    Each service plug-in must implement QServicePluginInterface.

    Each plug-in may support multiple interfaces and may even provide multiple implementations
    for the same interface. Individual implementations are identified via
    QServiceInterfaceDescriptor. For a more detailed explanation of services and how they relate to
    interface and their implementations please see QServiceInterfaceDescriptor.

    \sa QServicePluginInterface, QServiceContext, QAbstractSecuritySession
*/

/*!
    \enum QServiceManager::Scope

    \value UserScope When adding and removing services, use a storage location
    specific to the current user (e.g. in the user's home directory). When
    searching for services and interface implementations, first search in the
    user-specific location; if the service or interface implementation
    is not found, search in the system-wide storage location.

    \value SystemScope When adding and removing services, use a system-wide
    storage location accessible to all users. When searching
    for services and interface implementations, search only in the system-wide
    storage location.
*/

/*!
    \fn void QServiceManager::serviceAdded(const QString& serviceName)

    This signal is emited whenever a new service with the given
    \a serviceName has been registered with the service manager.

    \sa addService()
*/

/*!
    \fn void QServiceManager::serviceRemoved(const QString& serviceName)

    This signal is emited whenever a service with the given
    \a serviceName has been deregistered with the service manager.

    \sa removeService()
*/

/*!
    Creates a service manager with the given \a parent.

    The scope will default to QServiceManager::UserScope.
*/
QServiceManager::QServiceManager(QObject *parent)
    : QObject(parent),
      d(new QServiceManagerPrivate)
{
    d->init(this, UserScope);
}

/*!
    Creates a service manager with the given \a scope and \a parent.
*/
QServiceManager::QServiceManager(Scope scope, QObject *parent)
    : QObject(parent),
      d(new QServiceManagerPrivate)
{
    d->init(this, scope);
}

/*!
    Destroys the service manager.
*/
QServiceManager::~QServiceManager()
{
    d->database->close();
    delete d->database;
    delete d;
}

/*!
    Returns the scope used for registering and searching of services.
*/
QServiceManager::Scope QServiceManager::scope() const
{
    return d->scope;
}

/*!
    Returns a list of the services that provide the interface specified by
    \a interfaceName.
*/
QStringList QServiceManager::findServices(const QString& interfaceName) const
{
    QStringList services;
    QList<ServiceInfo> serviceInfoList;
    if (!d->database->isOpen())
        return services;
    services = d->database->getServiceNames(interfaceName);
    return services;
}

/*!
    Returns a list of the interfaces that match the specified \a filter.
*/
QList<QServiceInterfaceDescriptor> QServiceManager::findInterfaces(const QServiceFilter& filter) const
{
    if (!d->database->isOpen())
        return QList<QServiceInterfaceDescriptor>();
    bool ok = false;
    QList<QServiceInterfaceDescriptor> descriptors = d->database->getInterfaces(filter, &ok);
    if (!ok)
        return QList<QServiceInterfaceDescriptor>();
    return descriptors;
}

/*!
    Returns a list of the interfaces provided by the service named
    \a serviceName.
*/
QList<QServiceInterfaceDescriptor> QServiceManager::findInterfaces(const QString& serviceName) const
{
    QServiceFilter filter;
    if (!serviceName.isEmpty())
        filter.setServiceName(serviceName);
    return findInterfaces(filter);
}

/*!
    Loads and returns the interface specified by \a interfaceName, as
    provided by the default service for this interface, using the given
    \a context and \a session. \a context and \a session object are owned
    by the caller of this function.

    The caller takes ownership of the returned pointer.

    This function returns a null pointer if the requested service cannot be found.
*/
QObject* QServiceManager::loadInterface(const QString& interfaceName, QServiceContext* context, QAbstractSecuritySession* session)
{
    return loadInterface(defaultServiceInterface(interfaceName), context, session);
}

/*!
    Loads and returns the interface specified by \a descriptor using the
    given \a context and \a session. \a context and \a session object are owned
    by the caller of this function.

    The caller takes ownership of the returned pointer.

    This function returns a null pointer if the requested service cannot be found.
*/
QObject* QServiceManager::loadInterface(const QServiceInterfaceDescriptor& descriptor, QServiceContext* context, QAbstractSecuritySession* session)
{
    if (!descriptor.isValid()) {
        qWarning() << "QServiceManager::loadInterface() given invalid descriptor";
        return 0;
    }

    const QStringList serviceCaps = descriptor.property(QServiceInterfaceDescriptor::Capabilities).toStringList();
    if ( session && !session->isAllowed(serviceCaps) )
        return 0;  //TODO set error state on context object, if it exists

    QString serviceFilePath = qservicemanager_resolveLibraryPath(
            descriptor.property(QServiceInterfaceDescriptor::Location).toString());
    if (serviceFilePath.isEmpty()) {
        qWarning() << "QServiceManager::loadInterface() cannot locate library file for plugin:"
                << descriptor.property(QServiceInterfaceDescriptor::Location).toString();
        return 0;
    }

    QPluginLoader *loader = new QPluginLoader(serviceFilePath);
    QServicePluginInterface *pluginIFace = qobject_cast<QServicePluginInterface *>(loader->instance());

    if (pluginIFace) {
        QObject *obj = pluginIFace->createInstance(descriptor, context, session);
        if (obj) {
            QServicePluginCleanup *cleanup = new QServicePluginCleanup(loader, pluginIFace);
            QObject::connect(obj, SIGNAL(destroyed()), cleanup, SLOT(deleteLater()));
            return obj;
        }
        delete pluginIFace;
    }

    qWarning() << "QServiceManager::loadInterface() cannot load plugin at"
            << serviceFilePath << ":" << loader->errorString();
    loader->unload();
    delete loader;

    return 0;
}

/*!
    \fn T* QServiceManager::getInterface(const QString& interfaceName, QServiceContext* context, QAbstractSecuritySession* session)

    Loads the service object implementing \a interfaceName,
    as provided by the default service for this interface, using the given
    \a context and \a session. \a context and \a session object are owned
    by the caller of this function. The template class must be derived from QObject.

    If \a interfaceName is not a known interface the returned pointer will be null.

    The caller takes ownership of the returned pointer.
*/

/*!
    \fn T* QServiceManager::getInterface(const QServiceInterfaceDescriptor& serviceDescriptor, QServiceContext* context, QAbstractSecuritySession* session)

    Loads the service object identified by \a serviceDescriptor
    using the given \a context and \a session. \a context and \a session object are owned
    by the caller of this function. The template class must be derived from QObject.

    If the \a serviceDescriptor is not valid the returned pointer will be null.

    The caller takes ownership of the returned pointer.
*/

/*!
    Registers the service defined by the XML file at \a xmlFilePath.
    Returns true if the registration succeeded, and false otherwise.

    If a previously unkown interface is added the newly registered service automatically
    becomes the new default service provider for the new interface.

    A service plugin cannot be added if another service is already registered
    with the same plugin file path.  A service plugin also cannot be added if
    the service is already registered and implements any of the same interface
    versions that the new plugin implements.

    \sa setDefaultServiceForInterface()
*/
bool QServiceManager::addService(const QString& xmlFilePath)
{
    QFile *f = new QFile(xmlFilePath);
    bool b = addService(f);
    delete f;
    return b;
}

/*!
    Registers the service defined by the XML data from the given \a device.
    Returns true if the registration succeeded, and false otherwise. If a
    previously unkown interface is added the newly registered service
    automatically becomes the new default service provider for the new
    interface.

    Registering a service also causes QServicePluginInterface::installService()
    to be called on the service. If the service plugin is not accessible
    (e.g. if the plugin file is not found) and \c installService() cannot
    be invoked on the service, the registration fails and this method returns
    false.

    A service plugin cannot be added if another service is already registered
    with the same plugin file path.  A service plugin also cannot be added if
    the service is already registered and implements any of the same interface
    versions that the new plugin implements.

    \sa setDefaultServiceForInterface()
*/
bool QServiceManager::addService(QIODevice *device)
{
    if (!d->database->isOpen())
        return false;
    ServiceMetaData data(device);
    if (!data.extractMetadata())
        return false;

    bool result = d->database->registerService(data);
    if (result) {
        QPluginLoader *loader = new QPluginLoader(qservicemanager_resolveLibraryPath(data.location()));
        QServicePluginInterface *pluginIFace = qobject_cast<QServicePluginInterface *>(loader->instance());
        if (pluginIFace) {
            pluginIFace->installService();
        } else {
            result = false;
            d->database->unregisterService(data.name());
        }
        loader->unload();
        delete loader;
    }
    return result;
}

/*!
    Unregisters the service specified by \a serviceName.

    Returns true if the unregistration succeeded, and false otherwise.

    If a default service implementation is removed and there are other implementations
    for the same interface, the service manager chooses the implementation with the
    highest version number as the new default.  If there is more than one serivce
    with the same version number, the service manager makes a random choice with
    regards to the new default implementation. If this is
    not the desired behaviour the default selection should be updated
    via setDefaultServiceForInterface().
*/
bool QServiceManager::removeService(const QString& serviceName)
{
    if (!d->database->isOpen())
        return false;
    if (serviceName.isEmpty())
        return false;

    // Call QServicePluginInterface::uninstallService() on all plugins that
    // match this service

    QSet<QString> pluginPathsSet;
    QList<QServiceInterfaceDescriptor> descriptors = findInterfaces(serviceName);
    for (int i=0; i<descriptors.count(); i++)
        pluginPathsSet << descriptors[i].property(QServiceInterfaceDescriptor::Location).toString();

    QList<QString> pluginPaths = pluginPathsSet.toList();
    for (int i=0; i<pluginPaths.count(); i++) {
        QPluginLoader *loader = new QPluginLoader(qservicemanager_resolveLibraryPath(pluginPaths[i]));
        QServicePluginInterface *pluginIFace = qobject_cast<QServicePluginInterface *>(loader->instance());
        if (pluginIFace)
            pluginIFace->uninstallService();
        else
            qWarning() << "QServiceManager: unable to invoke uninstallService() on removed service";
        loader->unload();
        delete loader;
    }

    return d->database->unregisterService(serviceName);
}

/*!
    Sets the default interface implementation for \a interfaceName to the
    matching interface implementation provided by \a service.

    If \a service provides more than one interface implementation for
    \a interfaceName, the newest version of the interface is set as the
    default.

    Returns true if the operation succeeded, and false otherwise.
*/
bool QServiceManager::setDefaultServiceForInterface(const QString &service, const QString &interfaceName)
{
    if (!d->database->isOpen())
        return false;
    if (interfaceName.isEmpty() || service.isEmpty())
        return false;
    return d->database->setDefaultService(service, interfaceName);
}

/*!
    \overload

    Sets the interface implementation specified by \a descriptor to be the
    default implementation for the particular interface specified in the
    descriptor.

    Returns true if the operation succeeded, and false otherwise.
*/
bool QServiceManager::setDefaultServiceForInterface(const QServiceInterfaceDescriptor& descriptor)
{
    if (!d->database->isOpen())
        return false;
    if (!descriptor.isValid())
        return false;
    return d->database->setDefaultService(descriptor);
}

/*!
    Returns the default interface for the given \a interfaceName.
*/
QServiceInterfaceDescriptor QServiceManager::defaultServiceInterface(const QString& interfaceName) const
{
    if (!d->database->isOpen())
        return QServiceInterfaceDescriptor();
    bool ok = false;
    QServiceInterfaceDescriptor info;
    info = d->database->defaultServiceInterface(interfaceName, &ok);
    if (!ok)
        return QServiceInterfaceDescriptor();

    return info;
}

QT_END_NAMESPACE

#include "qservicemanager.moc"
<|endoftext|>