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

  Program:   Visualization Toolkit
  Module:    vtkExtractSelectedGraph.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.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkExtractSelectedGraph.h"

#include "vtkCellData.h"
#include "vtkCommand.h"
#include "vtkDataArray.h"
#include "vtkEventForwarderCommand.h"
#include "vtkExtractSelection.h"
#include "vtkGraph.h"
#include "vtkGraphIdList.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkSelection.h"
#include "vtkSignedCharArray.h"
#include "vtkSmartPointer.h"
#include "vtkStringArray.h"

#include <vtksys/stl/map>
using vtksys_stl::map;

vtkCxxRevisionMacro(vtkExtractSelectedGraph, "1.8");
vtkStandardNewMacro(vtkExtractSelectedGraph);

vtkExtractSelectedGraph::vtkExtractSelectedGraph()
{
  this->SetNumberOfInputPorts(2);
  this->RemoveIsolatedVertices = true;
}

vtkExtractSelectedGraph::~vtkExtractSelectedGraph()
{
}

int vtkExtractSelectedGraph::FillInputPortInformation(int port, vtkInformation* info)
{
  if (port == 0)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkAbstractGraph");
    return 1;
    }
  else if (port == 1)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkSelection");
    return 1;
    }
  return 0;
}

void vtkExtractSelectedGraph::SetSelectionConnection(vtkAlgorithmOutput* in)
{
  this->SetInputConnection(1, in);
}

int vtkExtractSelectedGraph::ConvertToIndexSelection(
  vtkSelection* selection,
  vtkDataSet* input,
  vtkSelection* outputSelection)
{
  // Change the selection to preserve topology
  vtkSelection* selTemp = vtkSelection::New();
  selTemp->ShallowCopy(selection);
  selTemp->GetProperties()->Set(vtkSelection::PRESERVE_TOPOLOGY(), true);

  // Use the extraction filter to create an insidedness array.
  vtkExtractSelection* const extract = vtkExtractSelection::New();
  extract->SetInput(0, input);
  extract->SetInput(1, selTemp);
  extract->Update();
  vtkDataSet* const extracted = extract->GetOutput();
  selTemp->Delete();

  outputSelection->GetProperties()->Set(vtkSelection::CONTENT_TYPE(), vtkSelection::INDICES);
  int type = selection->GetProperties()->Get(vtkSelection::FIELD_TYPE());
  outputSelection->GetProperties()->Set(vtkSelection::FIELD_TYPE(), type);
  vtkSignedCharArray* insidedness = 0;
  if (type == vtkSelection::CELL)
    {
    insidedness = vtkSignedCharArray::SafeDownCast(
      extracted->GetCellData()->GetAbstractArray("vtkInsidedness"));
    }
  else if (type == vtkSelection::POINT)
    {
    insidedness = vtkSignedCharArray::SafeDownCast(
      extracted->GetPointData()->GetAbstractArray("vtkInsidedness"));
    }
  else
    {
    vtkErrorMacro("Unknown field type");
    extract->Delete();
    return 0;
    }

  if (!insidedness)
    {
    vtkErrorMacro("Did not find expected vtkInsidedness array.");
    extract->Delete();
    return 0;
    }

  // Convert the insidedness array into an index selection.
  vtkIdTypeArray* indexArray = vtkIdTypeArray::New();
  for (vtkIdType i = 0; i < insidedness->GetNumberOfTuples(); i++)
    {
    if (insidedness->GetValue(i) == 1)
      {
      indexArray->InsertNextValue(i);
      }
    }
  outputSelection->SetSelectionList(indexArray);
  indexArray->Delete();
  extract->Delete();
  return 1;
}

int vtkExtractSelectedGraph::RequestData(
  vtkInformation* vtkNotUsed(request),
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  vtkAbstractGraph* input = vtkAbstractGraph::GetData(inputVector[0]);
  vtkSelection* selection = vtkSelection::GetData(inputVector[1]);

  // If there is nothing in the list, there is nothing to select.
  vtkAbstractArray* list = selection->GetSelectionList();
  if (!list || list->GetNumberOfTuples() == 0)
    {
    return 1;
    }

  vtkSelection* indexSelection = vtkSelection::New();
  indexSelection->ShallowCopy(selection);

  int content = selection->GetProperties()->Get(selection->CONTENT_TYPE());
  if (content != vtkSelection::INDICES)
    {
    // Convert the selection to an INDICES selection
    int ret = this->ConvertToIndexSelection(selection, input, indexSelection);
    if (ret != 1)
      {
      vtkErrorMacro("Selection conversion to INDICES failed.");
      indexSelection->Delete();
      return 0;
      }
    }
  vtkAbstractArray* arr = indexSelection->GetSelectionList();
  if (arr == NULL)
    {
    vtkErrorMacro("Selection list not found.");
    return 0;
    }
  vtkIdTypeArray* selectArr = vtkIdTypeArray::SafeDownCast(arr);
  if (selectArr == NULL)
    {
    vtkErrorMacro("Selection list must be of type vtkIdTypeArray.");
    return 0;
    }
  vtkIdType selectSize = selectArr->GetNumberOfTuples();

  vtkGraph* output = vtkGraph::GetData(outputVector);

  output->SetDirected(input->GetDirected());
  output->GetFieldData()->PassData(input->GetFieldData());

  if (selection->GetProperties()->Has(vtkSelection::FIELD_TYPE()) &&
      selection->GetProperties()->Get(vtkSelection::FIELD_TYPE()) == vtkSelection::CELL)
    {
    //
    // Edge selection
    //

    // Copy all vertices
    output->SetNumberOfVertices(input->GetNumberOfVertices());

    // Copy selected edges
    vtkCellData* inputEdgeData = input->GetEdgeData();
    vtkCellData* outputEdgeData = output->GetEdgeData();
    outputEdgeData->CopyAllocate(inputEdgeData);
    for (vtkIdType i = 0; i < selectSize; i++)
      {
      vtkIdType inputEdge = selectArr->GetValue(i);
      if (inputEdge < input->GetNumberOfEdges())
        {
        vtkIdType source = input->GetSourceVertex(inputEdge);
        vtkIdType target = input->GetTargetVertex(inputEdge);
        vtkIdType outputEdge = output->AddEdge(source, target);
        outputEdgeData->CopyData(inputEdgeData, inputEdge, outputEdge);
        }
      }

    // Remove isolated vertices
    if (this->RemoveIsolatedVertices)
      {
      output->GetVertexData()->DeepCopy(input->GetVertexData());
      output->GetPoints()->DeepCopy(input->GetPoints());
      vtkIdTypeArray* isolated = vtkIdTypeArray::New();
      for (vtkIdType i = 0; i < output->GetNumberOfVertices(); i++)
        {
        if (output->GetDegree(i) == 0)
          {
          isolated->InsertNextValue(i);
          }
        }
      output->RemoveVertices(isolated->GetPointer(0), isolated->GetNumberOfTuples());
      isolated->Delete();
      }
    else
      {
      output->GetVertexData()->PassData(input->GetVertexData());
      output->GetPoints()->ShallowCopy(input->GetPoints());
      }
    }
  else
    {
    //
    // Vertex selection
    //

    // Copy selected vertices
    double pt[3];
    vtkPoints* inputPoints = input->GetPoints();
    vtkPoints* outputPoints = vtkPoints::New();
    vtkPointData* inputVertexData = input->GetVertexData();
    vtkPointData* outputVertexData = output->GetVertexData();
    outputVertexData->CopyAllocate(inputVertexData);
    map<vtkIdType, vtkIdType> idMap;
    for (vtkIdType i = 0; i < selectSize; i++)
      {
      vtkIdType inputVertex = selectArr->GetValue(i);
      if (inputVertex < input->GetNumberOfVertices())
        {
        vtkIdType outputVertex = output->AddVertex();
        outputVertexData->CopyData(inputVertexData, inputVertex, outputVertex);
        idMap[inputVertex] = outputVertex;
        inputPoints->GetPoint(inputVertex, pt);
        outputPoints->InsertNextPoint(pt);
        }
      }
    output->SetPoints(outputPoints);
    outputPoints->Delete();

    // Copy any edges that connect selected vertices
    vtkCellData* inputEdgeData = input->GetEdgeData();
    vtkCellData* outputEdgeData = output->GetEdgeData();
    outputEdgeData->CopyAllocate(inputEdgeData);
    vtkGraphIdList* edgeList = vtkGraphIdList::New();
    for (vtkIdType i = 0; i < selectSize; i++)
      {
      vtkIdType inputVertex = selectArr->GetValue(i);
      if (idMap.count(inputVertex) > 0)
        {
        vtkIdType outputVertex = idMap[inputVertex];
        input->GetOutEdges(inputVertex, edgeList);
        for (vtkIdType j = 0; j < edgeList->GetNumberOfIds(); j++)
          {
          vtkIdType inputEdge = edgeList->GetId(j);
          vtkIdType oppInputVertex = input->GetOppositeVertex(inputEdge, inputVertex);
          if (idMap.count(oppInputVertex) > 0)
            {
            vtkIdType oppOutputVertex = idMap[oppInputVertex];
            vtkIdType outputEdge = output->AddEdge(outputVertex, oppOutputVertex);
            outputEdgeData->CopyData(inputEdgeData, inputEdge, outputEdge);
            }
          }
        }
      }
    edgeList->Delete();
    }

  // Clean up
  output->Squeeze();
  indexSelection->Delete();

  return 1;
}

void vtkExtractSelectedGraph::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "RemoveIsolatedVertices: "
     << (this->RemoveIsolatedVertices ? "on" : "off") << endl;
}

<commit_msg>BUG: Removed doubled edges bug when extracting vertices from an undirected graph.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkExtractSelectedGraph.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.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkExtractSelectedGraph.h"

#include "vtkCellData.h"
#include "vtkCommand.h"
#include "vtkDataArray.h"
#include "vtkEventForwarderCommand.h"
#include "vtkExtractSelection.h"
#include "vtkGraph.h"
#include "vtkGraphIdList.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkSelection.h"
#include "vtkSignedCharArray.h"
#include "vtkSmartPointer.h"
#include "vtkStringArray.h"

#include <vtksys/stl/map>
using vtksys_stl::map;

vtkCxxRevisionMacro(vtkExtractSelectedGraph, "1.9");
vtkStandardNewMacro(vtkExtractSelectedGraph);

vtkExtractSelectedGraph::vtkExtractSelectedGraph()
{
  this->SetNumberOfInputPorts(2);
  this->RemoveIsolatedVertices = true;
}

vtkExtractSelectedGraph::~vtkExtractSelectedGraph()
{
}

int vtkExtractSelectedGraph::FillInputPortInformation(int port, vtkInformation* info)
{
  if (port == 0)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkAbstractGraph");
    return 1;
    }
  else if (port == 1)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkSelection");
    return 1;
    }
  return 0;
}

void vtkExtractSelectedGraph::SetSelectionConnection(vtkAlgorithmOutput* in)
{
  this->SetInputConnection(1, in);
}

int vtkExtractSelectedGraph::ConvertToIndexSelection(
  vtkSelection* selection,
  vtkDataSet* input,
  vtkSelection* outputSelection)
{
  // Change the selection to preserve topology
  vtkSelection* selTemp = vtkSelection::New();
  selTemp->ShallowCopy(selection);
  selTemp->GetProperties()->Set(vtkSelection::PRESERVE_TOPOLOGY(), true);

  // Use the extraction filter to create an insidedness array.
  vtkExtractSelection* const extract = vtkExtractSelection::New();
  extract->SetInput(0, input);
  extract->SetInput(1, selTemp);
  extract->Update();
  vtkDataSet* const extracted = extract->GetOutput();
  selTemp->Delete();

  outputSelection->GetProperties()->Set(vtkSelection::CONTENT_TYPE(), vtkSelection::INDICES);
  int type = selection->GetProperties()->Get(vtkSelection::FIELD_TYPE());
  outputSelection->GetProperties()->Set(vtkSelection::FIELD_TYPE(), type);
  vtkSignedCharArray* insidedness = 0;
  if (type == vtkSelection::CELL)
    {
    insidedness = vtkSignedCharArray::SafeDownCast(
      extracted->GetCellData()->GetAbstractArray("vtkInsidedness"));
    }
  else if (type == vtkSelection::POINT)
    {
    insidedness = vtkSignedCharArray::SafeDownCast(
      extracted->GetPointData()->GetAbstractArray("vtkInsidedness"));
    }
  else
    {
    vtkErrorMacro("Unknown field type");
    extract->Delete();
    return 0;
    }

  if (!insidedness)
    {
    vtkErrorMacro("Did not find expected vtkInsidedness array.");
    extract->Delete();
    return 0;
    }

  // Convert the insidedness array into an index selection.
  vtkIdTypeArray* indexArray = vtkIdTypeArray::New();
  for (vtkIdType i = 0; i < insidedness->GetNumberOfTuples(); i++)
    {
    if (insidedness->GetValue(i) == 1)
      {
      indexArray->InsertNextValue(i);
      }
    }
  outputSelection->SetSelectionList(indexArray);
  indexArray->Delete();
  extract->Delete();
  return 1;
}

int vtkExtractSelectedGraph::RequestData(
  vtkInformation* vtkNotUsed(request),
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  vtkAbstractGraph* input = vtkAbstractGraph::GetData(inputVector[0]);
  vtkSelection* selection = vtkSelection::GetData(inputVector[1]);

  // If there is nothing in the list, there is nothing to select.
  vtkAbstractArray* list = selection->GetSelectionList();
  if (!list || list->GetNumberOfTuples() == 0)
    {
    return 1;
    }

  vtkSelection* indexSelection = vtkSelection::New();
  indexSelection->ShallowCopy(selection);

  int content = selection->GetProperties()->Get(selection->CONTENT_TYPE());
  if (content != vtkSelection::INDICES)
    {
    // Convert the selection to an INDICES selection
    int ret = this->ConvertToIndexSelection(selection, input, indexSelection);
    if (ret != 1)
      {
      vtkErrorMacro("Selection conversion to INDICES failed.");
      indexSelection->Delete();
      return 0;
      }
    }
  vtkAbstractArray* arr = indexSelection->GetSelectionList();
  if (arr == NULL)
    {
    vtkErrorMacro("Selection list not found.");
    return 0;
    }
  vtkIdTypeArray* selectArr = vtkIdTypeArray::SafeDownCast(arr);
  if (selectArr == NULL)
    {
    vtkErrorMacro("Selection list must be of type vtkIdTypeArray.");
    return 0;
    }
  vtkIdType selectSize = selectArr->GetNumberOfTuples();

  vtkGraph* output = vtkGraph::GetData(outputVector);

  output->SetDirected(input->GetDirected());
  output->GetFieldData()->PassData(input->GetFieldData());

  if (selection->GetProperties()->Has(vtkSelection::FIELD_TYPE()) &&
      selection->GetProperties()->Get(vtkSelection::FIELD_TYPE()) == vtkSelection::CELL)
    {
    //
    // Edge selection
    //

    // Copy all vertices
    output->SetNumberOfVertices(input->GetNumberOfVertices());

    // Copy selected edges
    vtkCellData* inputEdgeData = input->GetEdgeData();
    vtkCellData* outputEdgeData = output->GetEdgeData();
    outputEdgeData->CopyAllocate(inputEdgeData);
    for (vtkIdType i = 0; i < selectSize; i++)
      {
      vtkIdType inputEdge = selectArr->GetValue(i);
      if (inputEdge < input->GetNumberOfEdges())
        {
        vtkIdType source = input->GetSourceVertex(inputEdge);
        vtkIdType target = input->GetTargetVertex(inputEdge);
        vtkIdType outputEdge = output->AddEdge(source, target);
        outputEdgeData->CopyData(inputEdgeData, inputEdge, outputEdge);
        }
      }

    // Remove isolated vertices
    if (this->RemoveIsolatedVertices)
      {
      output->GetVertexData()->DeepCopy(input->GetVertexData());
      output->GetPoints()->DeepCopy(input->GetPoints());
      vtkIdTypeArray* isolated = vtkIdTypeArray::New();
      for (vtkIdType i = 0; i < output->GetNumberOfVertices(); i++)
        {
        if (output->GetDegree(i) == 0)
          {
          isolated->InsertNextValue(i);
          }
        }
      output->RemoveVertices(isolated->GetPointer(0), isolated->GetNumberOfTuples());
      isolated->Delete();
      }
    else
      {
      output->GetVertexData()->PassData(input->GetVertexData());
      output->GetPoints()->ShallowCopy(input->GetPoints());
      }
    }
  else
    {
    //
    // Vertex selection
    //

    // Copy selected vertices
    double pt[3];
    vtkPoints* inputPoints = input->GetPoints();
    vtkPoints* outputPoints = vtkPoints::New();
    vtkPointData* inputVertexData = input->GetVertexData();
    vtkPointData* outputVertexData = output->GetVertexData();
    outputVertexData->CopyAllocate(inputVertexData);
    map<vtkIdType, vtkIdType> idMap;
    for (vtkIdType i = 0; i < selectSize; i++)
      {
      vtkIdType inputVertex = selectArr->GetValue(i);
      if (inputVertex < input->GetNumberOfVertices())
        {
        vtkIdType outputVertex = output->AddVertex();
        outputVertexData->CopyData(inputVertexData, inputVertex, outputVertex);
        idMap[inputVertex] = outputVertex;
        inputPoints->GetPoint(inputVertex, pt);
        outputPoints->InsertNextPoint(pt);
        }
      }
    output->SetPoints(outputPoints);
    outputPoints->Delete();

    // Make a directed shallow copy of the graph so GetOutEdges()
    // returns every edge no more than once.
    vtkGraph* copy = vtkGraph::New();
    copy->ShallowCopy(input);
    copy->SetDirected(true);

    // Copy any edges that connect selected vertices
    vtkCellData* inputEdgeData = input->GetEdgeData();
    vtkCellData* outputEdgeData = output->GetEdgeData();
    outputEdgeData->CopyAllocate(inputEdgeData);
    vtkGraphIdList* edgeList = vtkGraphIdList::New();
    for (vtkIdType i = 0; i < selectSize; i++)
      {
      vtkIdType inputVertex = selectArr->GetValue(i);
      if (idMap.count(inputVertex) > 0)
        {
        vtkIdType outputVertex = idMap[inputVertex];
        copy->GetOutEdges(inputVertex, edgeList);
        for (vtkIdType j = 0; j < edgeList->GetNumberOfIds(); j++)
          {
          vtkIdType inputEdge = edgeList->GetId(j);
          vtkIdType oppInputVertex = input->GetOppositeVertex(inputEdge, inputVertex);
          if (idMap.count(oppInputVertex) > 0)
            {
            vtkIdType oppOutputVertex = idMap[oppInputVertex];
            vtkIdType outputEdge = output->AddEdge(outputVertex, oppOutputVertex);
            outputEdgeData->CopyData(inputEdgeData, inputEdge, outputEdge);
            }
          }
        }
      }
    edgeList->Delete();

    // Clean up
    copy->Delete();
    }

  // Clean up
  output->Squeeze();
  indexSelection->Delete();

  return 1;
}

void vtkExtractSelectedGraph::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "RemoveIsolatedVertices: "
     << (this->RemoveIsolatedVertices ? "on" : "off") << endl;
}

<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2017 Axel Waggershauser

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/Cr2Decompressor.h"
#include "common/Common.h"                // for unroll_loop, uint32, ushort16
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpJPEG.h"               // for BitStream<>::getBufferPosi...
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for min, copy_n, move
#include <cassert>                        // for assert

using std::copy_n;

namespace rawspeed {

void Cr2Decompressor::decodeScan()
{
  if (predictorMode != 1)
    ThrowRDE("Unsupported predictor mode.");

  if (slicesWidths.empty())
    slicesWidths.push_back(frame.w * frame.cps);

  bool isSubSampled = false;
  for (uint32 i = 0; i < frame.cps;  i++)
    isSubSampled = isSubSampled || frame.compInfo[i].superH != 1 ||
                   frame.compInfo[i].superV != 1;

  if (isSubSampled) {
    if (mRaw->isCFA)
      ThrowRDE("Cannot decode subsampled image to CFA data");

    if (mRaw->getCpp() != frame.cps)
      ThrowRDE("Subsampled component count does not match image.");

    if (frame.cps != 3 || frame.compInfo[0].superH != 2 ||
        (frame.compInfo[0].superV != 2 && frame.compInfo[0].superV != 1) ||
        frame.compInfo[1].superH != 1 || frame.compInfo[1].superV != 1 ||
        frame.compInfo[2].superH != 1 || frame.compInfo[2].superV != 1)
      ThrowRDE("Unsupported subsampling");

    if (frame.compInfo[0].superV == 2)
      decodeN_X_Y<3, 2, 2>(); // Cr2 sRaw1/mRaw
    else {
      assert(frame.compInfo[0].superV == 1);
      decodeN_X_Y<3, 2, 1>(); // Cr2 sRaw2/sRaw
    }
  } else {
    switch (frame.cps) {
    case 2:
      decodeN_X_Y<2, 1, 1>();
      break;
    case 4:
      decodeN_X_Y<4, 1, 1>();
      break;
    default:
      ThrowRDE("Unsupported number of components: %u", frame.cps);
    }
  }
}

void Cr2Decompressor::decode(std::vector<int> slicesWidths_)
{
  slicesWidths = move(slicesWidths_);
  AbstractLJpegDecompressor::decode();
}

// N_COMP == number of components (2, 3 or 4)
// X_S_F  == x/horizontal sampling factor (1 or 2)
// Y_S_F  == y/vertical   sampling factor (1 or 2)

template <int N_COMP, int X_S_F, int Y_S_F>
void Cr2Decompressor::decodeN_X_Y()
{
  auto ht = getHuffmanTables<N_COMP>();
  auto pred = getInitialPredictors<N_COMP>();
  auto predNext = reinterpret_cast<ushort16*>(mRaw->getDataUncropped(0, 0));

  BitPumpJPEG bitStream(input);

  uint32 pixelPitch = mRaw->pitch / 2; // Pitch in pixel
  if (frame.cps != 3 && frame.w * frame.cps > 2 * frame.h) {
    // Fix Canon double height issue where Canon doubled the width and halfed
    // the height (e.g. with 5Ds), ask Canon. frame.w needs to stay as is here
    // because the number of pixels after which the predictor gets updated is
    // still the doubled width.
    // see: FIX_CANON_HALF_HEIGHT_DOUBLE_WIDTH
    frame.h *= 2;
  }

  if (X_S_F == 2 && Y_S_F == 1)
  {
    // fix the inconsistent slice width in sRaw mode, ask Canon.
    for (auto& sliceWidth : slicesWidths)
      sliceWidth = sliceWidth * 3 / 2;
  }

  // To understand the CR2 slice handling and sampling factor behavior, see
  // https://github.com/lclevy/libcraw2/blob/master/docs/cr2_lossless.pdf?raw=true

  // inner loop decodes one group of pixels at a time
  //  * for <N,1,1>: N  = N*1*1 (full raw)
  //  * for <3,2,1>: 6  = 3*2*1
  //  * for <3,2,2>: 12 = 3*2*2
  // and advances x by N_COMP*X_S_F and y by Y_S_F
  constexpr int xStepSize = N_COMP * X_S_F;
  constexpr int yStepSize = Y_S_F;

  unsigned processedPixels = 0;
  unsigned processedLineSlices = 0;
  for (unsigned sliceWidth : slicesWidths) {
    for (unsigned y = 0; y < frame.h; y += yStepSize) {
      // Fix for Canon 80D mraw format.
      // In that format, `frame` is 4032x3402, while `mRaw` is 4536x3024.
      // Consequently, the slices in `frame` wrap around plus there are few
      // 'extra' sliced lines because sum(slicesW) * sliceH > mRaw->dim.area()
      // Those would overflow, hence the break.
      // see FIX_CANON_FRAME_VS_IMAGE_SIZE_MISMATCH
      unsigned destY = processedLineSlices % mRaw->dim.y;
      unsigned destX =
          processedLineSlices / mRaw->dim.y * slicesWidths[0] / mRaw->getCpp();
      if (destX >= static_cast<unsigned>(mRaw->dim.x))
        break;
      auto dest =
          reinterpret_cast<ushort16*>(mRaw->getDataUncropped(destX, destY));

      for (unsigned x = 0; x < sliceWidth; x += xStepSize) {
        // check if we processed one full raw row worth of pixels
        if (processedPixels == frame.w) {
          // if yes -> update predictor by going back exactly one row,
          // no matter where we are right now.
          // makes no sense from an image compression point of view, ask Canon.
          copy_n(predNext, N_COMP, pred.data());
          predNext = dest;
          processedPixels = 0;
        }

        if (X_S_F == 1) { // will be optimized out
          unroll_loop<N_COMP>([&](int i) {
            *dest++ = pred[i] += ht[i]->decodeNext(bitStream);
          });
        } else {
          unroll_loop<Y_S_F>([&](int i) {
            dest[0 + i*pixelPitch] = pred[0] += ht[0]->decodeNext(bitStream);
            dest[3 + i*pixelPitch] = pred[0] += ht[0]->decodeNext(bitStream);
          });

          dest[1] = pred[1] += ht[1]->decodeNext(bitStream);
          dest[2] = pred[2] += ht[2]->decodeNext(bitStream);

          dest += xStepSize;
        }
        processedPixels += X_S_F;
      }
      processedLineSlices += yStepSize;
    }
  }
  input.skipBytes(bitStream.getBufferPosition());
}

} // namespace rawspeed
<commit_msg>Cr2Decompressor::decodeScan(): slightly verbosify subsampling check<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2017 Axel Waggershauser

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/Cr2Decompressor.h"
#include "common/Common.h"                // for unroll_loop, uint32, ushort16
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpJPEG.h"               // for BitStream<>::getBufferPosi...
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for min, copy_n, move
#include <cassert>                        // for assert

using std::copy_n;

namespace rawspeed {

void Cr2Decompressor::decodeScan()
{
  if (predictorMode != 1)
    ThrowRDE("Unsupported predictor mode.");

  if (slicesWidths.empty())
    slicesWidths.push_back(frame.w * frame.cps);

  bool isSubSampled = false;
  for (uint32 i = 0; i < frame.cps;  i++)
    isSubSampled = isSubSampled || frame.compInfo[i].superH != 1 ||
                   frame.compInfo[i].superV != 1;

  if (isSubSampled) {
    if (mRaw->isCFA)
      ThrowRDE("Cannot decode subsampled image to CFA data");

    if (mRaw->getCpp() != frame.cps)
      ThrowRDE("Subsampled component count does not match image.");

    if (frame.cps != 3)
      ThrowRDE("Unsupported number of subsampled components: %u", frame.cps);

    // see http://lclevy.free.fr/cr2/#sraw for overview table
    bool isSupported = frame.compInfo[0].superH == 2;

    isSupported = isSupported && (frame.compInfo[0].superV == 1 ||
                                  frame.compInfo[0].superV == 2);

    for (uint32 i = 1; i < frame.cps; i++)
      isSupported = isSupported && frame.compInfo[i].superH == 1 &&
                    frame.compInfo[i].superV == 1;

    if (!isSupported) {
      ThrowRDE("Unsupported subsampling ([[%u, %u], [%u, %u], [%u, %u]])",
               frame.compInfo[0].superH, frame.compInfo[0].superV,
               frame.compInfo[1].superH, frame.compInfo[1].superV,
               frame.compInfo[2].superH, frame.compInfo[2].superV);
    }

    if (frame.compInfo[0].superV == 2)
      decodeN_X_Y<3, 2, 2>(); // Cr2 sRaw1/mRaw
    else {
      assert(frame.compInfo[0].superV == 1);
      decodeN_X_Y<3, 2, 1>(); // Cr2 sRaw2/sRaw
    }
  } else {
    switch (frame.cps) {
    case 2:
      decodeN_X_Y<2, 1, 1>();
      break;
    case 4:
      decodeN_X_Y<4, 1, 1>();
      break;
    default:
      ThrowRDE("Unsupported number of components: %u", frame.cps);
    }
  }
}

void Cr2Decompressor::decode(std::vector<int> slicesWidths_)
{
  slicesWidths = move(slicesWidths_);
  AbstractLJpegDecompressor::decode();
}

// N_COMP == number of components (2, 3 or 4)
// X_S_F  == x/horizontal sampling factor (1 or 2)
// Y_S_F  == y/vertical   sampling factor (1 or 2)

template <int N_COMP, int X_S_F, int Y_S_F>
void Cr2Decompressor::decodeN_X_Y()
{
  auto ht = getHuffmanTables<N_COMP>();
  auto pred = getInitialPredictors<N_COMP>();
  auto predNext = reinterpret_cast<ushort16*>(mRaw->getDataUncropped(0, 0));

  BitPumpJPEG bitStream(input);

  uint32 pixelPitch = mRaw->pitch / 2; // Pitch in pixel
  if (frame.cps != 3 && frame.w * frame.cps > 2 * frame.h) {
    // Fix Canon double height issue where Canon doubled the width and halfed
    // the height (e.g. with 5Ds), ask Canon. frame.w needs to stay as is here
    // because the number of pixels after which the predictor gets updated is
    // still the doubled width.
    // see: FIX_CANON_HALF_HEIGHT_DOUBLE_WIDTH
    frame.h *= 2;
  }

  if (X_S_F == 2 && Y_S_F == 1)
  {
    // fix the inconsistent slice width in sRaw mode, ask Canon.
    for (auto& sliceWidth : slicesWidths)
      sliceWidth = sliceWidth * 3 / 2;
  }

  // To understand the CR2 slice handling and sampling factor behavior, see
  // https://github.com/lclevy/libcraw2/blob/master/docs/cr2_lossless.pdf?raw=true

  // inner loop decodes one group of pixels at a time
  //  * for <N,1,1>: N  = N*1*1 (full raw)
  //  * for <3,2,1>: 6  = 3*2*1
  //  * for <3,2,2>: 12 = 3*2*2
  // and advances x by N_COMP*X_S_F and y by Y_S_F
  constexpr int xStepSize = N_COMP * X_S_F;
  constexpr int yStepSize = Y_S_F;

  unsigned processedPixels = 0;
  unsigned processedLineSlices = 0;
  for (unsigned sliceWidth : slicesWidths) {
    for (unsigned y = 0; y < frame.h; y += yStepSize) {
      // Fix for Canon 80D mraw format.
      // In that format, `frame` is 4032x3402, while `mRaw` is 4536x3024.
      // Consequently, the slices in `frame` wrap around plus there are few
      // 'extra' sliced lines because sum(slicesW) * sliceH > mRaw->dim.area()
      // Those would overflow, hence the break.
      // see FIX_CANON_FRAME_VS_IMAGE_SIZE_MISMATCH
      unsigned destY = processedLineSlices % mRaw->dim.y;
      unsigned destX =
          processedLineSlices / mRaw->dim.y * slicesWidths[0] / mRaw->getCpp();
      if (destX >= static_cast<unsigned>(mRaw->dim.x))
        break;
      auto dest =
          reinterpret_cast<ushort16*>(mRaw->getDataUncropped(destX, destY));

      for (unsigned x = 0; x < sliceWidth; x += xStepSize) {
        // check if we processed one full raw row worth of pixels
        if (processedPixels == frame.w) {
          // if yes -> update predictor by going back exactly one row,
          // no matter where we are right now.
          // makes no sense from an image compression point of view, ask Canon.
          copy_n(predNext, N_COMP, pred.data());
          predNext = dest;
          processedPixels = 0;
        }

        if (X_S_F == 1) { // will be optimized out
          unroll_loop<N_COMP>([&](int i) {
            *dest++ = pred[i] += ht[i]->decodeNext(bitStream);
          });
        } else {
          unroll_loop<Y_S_F>([&](int i) {
            dest[0 + i*pixelPitch] = pred[0] += ht[0]->decodeNext(bitStream);
            dest[3 + i*pixelPitch] = pred[0] += ht[0]->decodeNext(bitStream);
          });

          dest[1] = pred[1] += ht[1]->decodeNext(bitStream);
          dest[2] = pred[2] += ht[2]->decodeNext(bitStream);

          dest += xStepSize;
        }
        processedPixels += X_S_F;
      }
      processedLineSlices += yStepSize;
    }
  }
  input.skipBytes(bitStream.getBufferPosition());
}

} // namespace rawspeed
<|endoftext|>


<commit_before>/**
 * MltFrame.cpp - MLT Wrapper
 * Copyright (C) 2004-2005 Charles Yates
 * Author: Charles Yates <charles.yates@pandora.be>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "MltFrame.h"
#include "MltProducer.h"
using namespace Mlt;

Frame::Frame( mlt_frame frame ) :
	Properties( false ),
	instance( frame )
{
	inc_ref( );
}

Frame::Frame( Frame &frame ) :
	Mlt::Properties( (mlt_properties)NULL ),
	instance( frame.get_frame( ) )
{
	inc_ref( );
}

Frame::~Frame( )
{
	mlt_frame_close( instance );
}

mlt_frame Frame::get_frame( )
{
	return instance;
}

mlt_properties Frame::get_properties( )
{
	return mlt_frame_properties( get_frame( ) );
}

uint8_t *Frame::get_image( mlt_image_format &format, int &w, int &h, int writable )
{
	uint8_t *image = NULL;
	if ( get_double( "consumer_aspect_ratio" ) == 0.0 )
		set( "consumer_aspect_ratio", 1.0 );
	mlt_frame_get_image( get_frame( ), &image, &format, &w, &h, writable );
	set( "format", format );
	set( "writable", writable );
	return image;
}

unsigned char *Frame::fetch_image( mlt_image_format f, int w, int h, int writable )
{
	uint8_t *image = NULL;
	if ( get_double( "consumer_aspect_ratio" ) == 0.0 )
		set( "consumer_aspect_ratio", 1.0 );
	mlt_frame_get_image( get_frame( ), &image, &f, &w, &h, writable );
	set( "format", f );
	set( "writable", writable );
	return image;
}

void *Frame::get_audio( mlt_audio_format &format, int &frequency, int &channels, int &samples )
{
	void *audio = NULL;
	mlt_frame_get_audio( get_frame( ), &audio, &format, &frequency, &channels, &samples );
	return audio;
}

unsigned char *Frame::get_waveform( int w, int h )
{
	return mlt_frame_get_waveform( get_frame( ), w, h );
}

Producer *Frame::get_original_producer( )
{
	return new Producer( mlt_frame_get_original_producer( get_frame( ) ) );
}

mlt_properties Frame::get_unique_properties( Service &service )
{
	return mlt_frame_unique_properties( get_frame(), service.get_service() );
}

int Frame::get_position( )
{
	return mlt_frame_get_position( get_frame() );
}

int Frame::set_image( uint8_t *image, int size, mlt_destructor destroy )
{
	return mlt_frame_set_image( get_frame(), image, size, destroy );
}

int Frame::set_alpha( uint8_t *alpha, int size, mlt_destructor destroy )
{
	return mlt_frame_set_alpha( get_frame(), alpha, size, destroy );
}
<commit_msg>Make the Mlt::Properties initialization match the copy constructor.<commit_after>/**
 * MltFrame.cpp - MLT Wrapper
 * Copyright (C) 2004-2005 Charles Yates
 * Author: Charles Yates <charles.yates@pandora.be>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "MltFrame.h"
#include "MltProducer.h"
using namespace Mlt;

Frame::Frame( mlt_frame frame ) :
	Mlt::Properties( (mlt_properties)NULL ),
	instance( frame )
{
	inc_ref( );
}

Frame::Frame( Frame &frame ) :
	Mlt::Properties( (mlt_properties)NULL ),
	instance( frame.get_frame( ) )
{
	inc_ref( );
}

Frame::~Frame( )
{
	mlt_frame_close( instance );
}

mlt_frame Frame::get_frame( )
{
	return instance;
}

mlt_properties Frame::get_properties( )
{
	return mlt_frame_properties( get_frame( ) );
}

uint8_t *Frame::get_image( mlt_image_format &format, int &w, int &h, int writable )
{
	uint8_t *image = NULL;
	if ( get_double( "consumer_aspect_ratio" ) == 0.0 )
		set( "consumer_aspect_ratio", 1.0 );
	mlt_frame_get_image( get_frame( ), &image, &format, &w, &h, writable );
	set( "format", format );
	set( "writable", writable );
	return image;
}

unsigned char *Frame::fetch_image( mlt_image_format f, int w, int h, int writable )
{
	uint8_t *image = NULL;
	if ( get_double( "consumer_aspect_ratio" ) == 0.0 )
		set( "consumer_aspect_ratio", 1.0 );
	mlt_frame_get_image( get_frame( ), &image, &f, &w, &h, writable );
	set( "format", f );
	set( "writable", writable );
	return image;
}

void *Frame::get_audio( mlt_audio_format &format, int &frequency, int &channels, int &samples )
{
	void *audio = NULL;
	mlt_frame_get_audio( get_frame( ), &audio, &format, &frequency, &channels, &samples );
	return audio;
}

unsigned char *Frame::get_waveform( int w, int h )
{
	return mlt_frame_get_waveform( get_frame( ), w, h );
}

Producer *Frame::get_original_producer( )
{
	return new Producer( mlt_frame_get_original_producer( get_frame( ) ) );
}

mlt_properties Frame::get_unique_properties( Service &service )
{
	return mlt_frame_unique_properties( get_frame(), service.get_service() );
}

int Frame::get_position( )
{
	return mlt_frame_get_position( get_frame() );
}

int Frame::set_image( uint8_t *image, int size, mlt_destructor destroy )
{
	return mlt_frame_set_image( get_frame(), image, size, destroy );
}

int Frame::set_alpha( uint8_t *alpha, int size, mlt_destructor destroy )
{
	return mlt_frame_set_alpha( get_frame(), alpha, size, destroy );
}
<|endoftext|>


<commit_before>#include "mode_calc_rmsd.hpp"

#include <mill/util/file_extension.hpp>
#include <mill/util/cmdarg.hpp>
#include <mill/math/BestFitStructure.hpp>
#include <mill/pdb/PDBReader.hpp>
#include <mill/traj.hpp>
#include <fstream>

namespace mill
{

const char* mode_calc_rmsd_usage() noexcept
{
    return "usage: mill calc rmsd [traj file] [ref file]\n"
           "optinal args:\n"
           "    --align=(true|false) [by default, true]\n"
           "        If true (default), perform alignment by minimizing RMSD.\n"
           "        otherwise, it calculates RMSD without minimization.\n"
           "    --output=<filename>  [by default, \"mill_rmsd.dat\"]\n"
           "        output data file.\n"
           "    --only=<begin>:<end>\n"
           "    --ref-only=<begin>:<end>\n"
           "        use [begin, end) region only.\n";
}

std::optional<std::pair<std::size_t, std::size_t>>
pop_range(std::deque<std::string_view>& args, std::string_view name)
{
    if(const auto arg = pop_argument<std::string>(args, name))
    {
        return std::make_optional<std::pair<std::size_t, std::size_t>>(
                std::stoull(arg->substr(0, arg->find(':'))),
                std::stoull(arg->substr(arg->find(':') + 1)));
    }
    else
    {
        return std::nullopt;
    }
}

double rmsd(const std::vector<Vector<double, 3>>& lhs,
            const std::vector<Vector<double, 3>>& rhs)
{
    const std::size_t s = lhs.size();
    if(s != rhs.size())
    {
        log::fatal("mill calc rmsd: size differs");
    }

    double sigma = 0.;
    for(std::size_t i=0; i<s; ++i)
    {
        sigma += length_sq(lhs[i] - rhs[i]);
    }
    return std::sqrt(sigma / static_cast<double>(s));
}

int mode_calc_rmsd(std::deque<std::string_view> args)
{
    using vector_type = Vector<double, 3>;

    // remove unordered argumnets
    const auto do_align = pop_argument<bool       >(args, "align" ).value_or(true);
    const auto output   = pop_argument<std::string>(args, "output").value_or("mill_rmsd.dat");

    if(args.empty())
    {
        log::error("mill calc rmsd: too few arguments.");
        log::error(mode_calc_rmsd_usage());
        return 1;
    }

    const auto only     = pop_range(args, "only");
    const auto ref_only = pop_range(args, "ref-only");

    log::debug("only     = ", only);
    log::debug("ref_only = ", ref_only);

    const auto fname = args.front();
    if(fname == "help")
    {
        log::info(mode_calc_rmsd_usage());
        return 0;
    }

    if(fname.size() < 5)
    {
        log::error("mill calc rmsd: unknown file format: ", fname);
        log::error(mode_calc_rmsd_usage());
        return 1;
    }

    const auto refname = args.at(1);
    std::vector<vector_type> ref;
    {
        log::info("mill calc rmsd: reading ", refname, " as a reference file...");
        auto r = reader(refname);
        r.read_header();
        if(const auto first_frame = r.read_frame())
        {
            if(ref_only)
            {
                const auto [first, last] = *ref_only;
                if(first_frame->size() <= first || first_frame->size() < last)
                {
                    log::fatal("The range specified by --ref-only (", *ref_only,
                        ") exceeds the size of snapshot (", first_frame->size(),
                        ").");
                }
                for(std::size_t i=first; i<last; ++i)
                {
                    ref.push_back(first_frame->at(i).position());
                }
            }
            else
            {
                for(const auto& particle : *first_frame)
                {
                    ref.push_back(particle.position());
                }
            }
        }
        log::info("mill calc rmsd: done. reference structure has ",
                  ref.size(), " particles.");
    }

    std::ofstream ofs(output);
    ofs << "#t rmsd\n";
    if(do_align)
    {
        BestFit<double> bestfit;
        bestfit.set_reference(ref);

        std::size_t tstep = 0;
        for(const auto& frame : reader(fname))
        {
            std::vector<Vector<double, 3>> snapshot;
            if(only)
            {
                const auto [first, last] = *only;
                if(frame.size() <= first || frame.size() < last)
                {
                    log::fatal("The range specified by --only (", *only,
                        ") exceeds the size of snapshot (", frame.size(), ").");
                }
                for(std::size_t i=first; i<last; ++i)
                {
                    snapshot.push_back(frame.at(i).position());
                }
            }
            else
            {
                snapshot.reserve(frame.size());
                for(const auto& particle : frame)
                {
                    snapshot.push_back(particle.position());
                }
            }
            ofs << tstep << ' ' << rmsd(ref, bestfit.fit(snapshot)) << '\n';
            ++tstep;
        }
    }
    else
    {
        std::size_t tstep = 0;
        for(const auto& frame : reader(fname))
        {
            std::vector<Vector<double, 3>> snapshot;
            if(only)
            {
                const auto [first, last] = *only;
                if(frame.size() <= first || frame.size() < last)
                {
                    log::fatal("The range specified by --only (", *only,
                        ") exceeds the size of snapshot (", frame.size(), ").");
                }
                for(std::size_t i=first; i<last; ++i)
                {
                    snapshot.push_back(frame.at(i).position());
                }
            }
            else
            {
                snapshot.reserve(frame.size());
                for(const auto& particle : frame)
                {
                    snapshot.push_back(particle.position());
                }
            }
            ofs << tstep << ' ' << rmsd(ref, snapshot) << '\n';
            ++tstep;
        }
    }
    return 0;
}

}//mill
<commit_msg>:goal_net: pop unordered args before checking num of args<commit_after>#include "mode_calc_rmsd.hpp"

#include <mill/util/file_extension.hpp>
#include <mill/util/cmdarg.hpp>
#include <mill/math/BestFitStructure.hpp>
#include <mill/pdb/PDBReader.hpp>
#include <mill/traj.hpp>
#include <fstream>

namespace mill
{

const char* mode_calc_rmsd_usage() noexcept
{
    return "usage: mill calc rmsd [traj file] [ref file]\n"
           "optinal args:\n"
           "    --align=(true|false) [by default, true]\n"
           "        If true (default), perform alignment by minimizing RMSD.\n"
           "        otherwise, it calculates RMSD without minimization.\n"
           "    --output=<filename>  [by default, \"mill_rmsd.dat\"]\n"
           "        output data file.\n"
           "    --only=<begin>:<end>\n"
           "    --ref-only=<begin>:<end>\n"
           "        use [begin, end) region only.\n";
}

std::optional<std::pair<std::size_t, std::size_t>>
pop_range(std::deque<std::string_view>& args, std::string_view name)
{
    if(const auto arg = pop_argument<std::string>(args, name))
    {
        return std::make_optional<std::pair<std::size_t, std::size_t>>(
                std::stoull(arg->substr(0, arg->find(':'))),
                std::stoull(arg->substr(arg->find(':') + 1)));
    }
    else
    {
        return std::nullopt;
    }
}

double rmsd(const std::vector<Vector<double, 3>>& lhs,
            const std::vector<Vector<double, 3>>& rhs)
{
    const std::size_t s = lhs.size();
    if(s != rhs.size())
    {
        log::fatal("mill calc rmsd: size differs");
    }

    double sigma = 0.;
    for(std::size_t i=0; i<s; ++i)
    {
        sigma += length_sq(lhs[i] - rhs[i]);
    }
    return std::sqrt(sigma / static_cast<double>(s));
}

int mode_calc_rmsd(std::deque<std::string_view> args)
{
    using vector_type = Vector<double, 3>;

    // remove unordered argumnets
    const auto do_align = pop_argument<bool       >(args, "align" ).value_or(true);
    const auto output   = pop_argument<std::string>(args, "output").value_or("mill_rmsd.dat");

    const auto only     = pop_range(args, "only");
    const auto ref_only = pop_range(args, "ref-only");

    if(args.empty())
    {
        log::error("mill calc rmsd: too few arguments.");
        log::error(mode_calc_rmsd_usage());
        return 1;
    }

    log::debug("only     = ", only);
    log::debug("ref_only = ", ref_only);

    const auto fname = args.front();
    if(fname == "help")
    {
        log::info(mode_calc_rmsd_usage());
        return 0;
    }

    if(fname.size() < 5)
    {
        log::error("mill calc rmsd: unknown file format: ", fname);
        log::error(mode_calc_rmsd_usage());
        return 1;
    }

    const auto refname = args.at(1);
    std::vector<vector_type> ref;
    {
        log::info("mill calc rmsd: reading ", refname, " as a reference file...");
        auto r = reader(refname);
        r.read_header();
        if(const auto first_frame = r.read_frame())
        {
            if(ref_only)
            {
                const auto [first, last] = *ref_only;
                if(first_frame->size() <= first || first_frame->size() < last)
                {
                    log::fatal("The range specified by --ref-only (", *ref_only,
                        ") exceeds the size of snapshot (", first_frame->size(),
                        ").");
                }
                for(std::size_t i=first; i<last; ++i)
                {
                    ref.push_back(first_frame->at(i).position());
                }
            }
            else
            {
                for(const auto& particle : *first_frame)
                {
                    ref.push_back(particle.position());
                }
            }
        }
        log::info("mill calc rmsd: done. reference structure has ",
                  ref.size(), " particles.");
    }

    std::ofstream ofs(output);
    ofs << "#t rmsd\n";
    if(do_align)
    {
        BestFit<double> bestfit;
        bestfit.set_reference(ref);

        std::size_t tstep = 0;
        for(const auto& frame : reader(fname))
        {
            std::vector<Vector<double, 3>> snapshot;
            if(only)
            {
                const auto [first, last] = *only;
                if(frame.size() <= first || frame.size() < last)
                {
                    log::fatal("The range specified by --only (", *only,
                        ") exceeds the size of snapshot (", frame.size(), ").");
                }
                for(std::size_t i=first; i<last; ++i)
                {
                    snapshot.push_back(frame.at(i).position());
                }
            }
            else
            {
                snapshot.reserve(frame.size());
                for(const auto& particle : frame)
                {
                    snapshot.push_back(particle.position());
                }
            }
            ofs << tstep << ' ' << rmsd(ref, bestfit.fit(snapshot)) << '\n';
            ++tstep;
        }
    }
    else
    {
        std::size_t tstep = 0;
        for(const auto& frame : reader(fname))
        {
            std::vector<Vector<double, 3>> snapshot;
            if(only)
            {
                const auto [first, last] = *only;
                if(frame.size() <= first || frame.size() < last)
                {
                    log::fatal("The range specified by --only (", *only,
                        ") exceeds the size of snapshot (", frame.size(), ").");
                }
                for(std::size_t i=first; i<last; ++i)
                {
                    snapshot.push_back(frame.at(i).position());
                }
            }
            else
            {
                snapshot.reserve(frame.size());
                for(const auto& particle : frame)
                {
                    snapshot.push_back(particle.position());
                }
            }
            ofs << tstep << ' ' << rmsd(ref, snapshot) << '\n';
            ++tstep;
        }
    }
    return 0;
}

}//mill
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <stdio.h>
#include "Timer.h"
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

using namespace std;

void streamcp(char* infile, char* outfile);

void rdwr(char* infile, char* outfile);

void rdwrbuf(char* infile, char* outfile);

int main(int argc, char** argv) {
	if(argc < 3) {
		cout << "Error: Enter at least 2 files. " << endl;
	}
	else if(argc == 3) {
		rdwrbuf(argv[1], argv[2]);
	}
	else if(argc == 4) {
		double wt = 0, ut =0, st = 0;
		Timer wall, user, sys;

		sys.start();
		rdwrbuf(argv[1], argv[2]);
		if(-1 == sys.elapsedTime(wt,ut,st)) {
			cout << "Error with elapsedTime(). " << endl;
		}
		else {
			cout << "rdwrbuf: wt = " << wt << " ut = " << ut << " st = " << st << endl;
		}

		wall.start();
		streamcp(argv[1],argv[2]);
		if(-1 == wall.elapsedTime(wt,ut,st) ) {
			cout << "Error with elapsedTime(). " << endl;
		}
		else {
			cout << "stream: wt = " << wt << " ut = " << ut << " st = " << st << endl;
		}

		user.start();
		rdwr(argv[1], argv[2]);
		if(-1 == user.elapsedTime(wt,ut,st) ) {
			cout << "Error with elapsedTime(). " << endl;
		}
		else {
			cout << "rdwr: wt = " << wt << " ut = " << ut << " st = " << st << endl;
		}

	}
	else {
		cout << "Error: too many arguements" << endl;
	}

	return 0;
}

void streamcp(char* infile, char* outfile) {
	ifstream ifs;
	ofstream ofs;
	ifs.open(infile);
	ofs.open(outfile);
	char c;
	while(ifs.good() && ifs.get(c)) {
		ofs.put(c);
	}
	ifs.close();
	ofs.close();
}

void rdwrbuf(char* infile, char* outfile) {
	int fdin;
	int fdout;
	if(-1 == (fdout = open(outfile, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR))) {
		perror("There was an error with open(). ");
		exit(1);
	}
	if(-1 == (fdin = open(infile, O_RDONLY))) {
		perror("There was an error with open(). ");
		exit(1);
	}
	char c[BUFSIZ];
	int size;
	if(-1 == (size = read(fdin, c, sizeof(c)))) {
		perror("There was an error with read().");
		exit(1);
	}
	while(size > 0) {
		if(-1 == write(fdout, c, size)) {
			perror("There was an error with write(). ");
			exit(1);
		}
		if(-1 == (size = read(fdin, c, sizeof(c)))) {
			perror("There was an error with read().");
			exit(1);
		}
	}
	if(-1 == close(fdout)) {
		perror("There was an error with close(). ");
		exit(1);
	}
	if(-1 == close(fdin)) {
		perror("There was an error with close(). ");
		exit(1);
	}
}

void rdwr(char* infile, char* outfile) {
	int fdin;
	int fdout;
	if(-1 == (fdout = open(outfile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR))) {
		perror("There was an error with open(). ");
		exit(1);
	}
	if(-1 == (fdin = open(infile, O_RDONLY))) {
		perror("There was an error with open(). ");
		exit(1);
	}
	char c[1];
	int size;
	if(-1 == (size = read(fdin, c, sizeof(c)))) {
		perror("There was an error with read().");
		exit(1);
	}
	while(size > 0) {
		if(-1 == write(fdout, c, size)) {
			perror("There was an error with write(). ");
			exit(1);
		}
		if(-1 == (size = read(fdin, c, sizeof(c)))) {
			perror("There was an error with read().");
			exit(1);
		}
	}
	if(-1 == close(fdout)) {
		perror("There was an error with close(). ");
		exit(1);
	}
	if(-1 == close(fdin)) {
		perror("There was an error with close(). ");
		exit(1);
	}
}
<commit_msg>checks for valid input file before valid output file<commit_after>#include <iostream>
#include <fstream>
#include <stdio.h>
#include "Timer.h"
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

using namespace std;

void streamcp(char* infile, char* outfile);

void rdwr(char* infile, char* outfile);

void rdwrbuf(char* infile, char* outfile);

int main(int argc, char** argv) {
	if(argc < 3) {
		cout << "Error: Enter at least 2 files. " << endl;
	}
	else if(argc == 3) {
		rdwrbuf(argv[1], argv[2]);
	}
	else if(argc == 4) {
		double wt = 0, ut =0, st = 0;
		Timer wall, user, sys;

		sys.start();
		rdwrbuf(argv[1], argv[2]);
		if(-1 == sys.elapsedTime(wt,ut,st)) {
			cout << "Error with elapsedTime(). " << endl;
		}
		else {
			cout << "rdwrbuf: wt = " << wt << " ut = " << ut << " st = " << st << endl;
		}

		wall.start();
		streamcp(argv[1],argv[2]);
		if(-1 == wall.elapsedTime(wt,ut,st) ) {
			cout << "Error with elapsedTime(). " << endl;
		}
		else {
			cout << "stream: wt = " << wt << " ut = " << ut << " st = " << st << endl;
		}

		user.start();
		rdwr(argv[1], argv[2]);
		if(-1 == user.elapsedTime(wt,ut,st) ) {
			cout << "Error with elapsedTime(). " << endl;
		}
		else {
			cout << "rdwr: wt = " << wt << " ut = " << ut << " st = " << st << endl;
		}

	}
	else {
		cout << "Error: too many arguements" << endl;
	}

	return 0;
}

void streamcp(char* infile, char* outfile) {
	ifstream ifs;
	ofstream ofs;
	ifs.open(infile);
	ofs.open(outfile);
	char c;
	while(ifs.good() && ifs.get(c)) {
		ofs.put(c);
	}
	ifs.close();
	ofs.close();
}

void rdwrbuf(char* infile, char* outfile) {
	int fdin;
	int fdout;
	if(-1 == (fdin = open(infile, O_RDONLY))) {
		perror("There was an error with open(). ");
		exit(1);
	}
	if(-1 == (fdout = open(outfile, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR))) {
		perror("There was an error with open(). ");
		exit(1);
	}
	char c[BUFSIZ];
	int size;
	if(-1 == (size = read(fdin, c, sizeof(c)))) {
		perror("There was an error with read().");
		exit(1);
	}
	while(size > 0) {
		if(-1 == write(fdout, c, size)) {
			perror("There was an error with write(). ");
			exit(1);
		}
		if(-1 == (size = read(fdin, c, sizeof(c)))) {
			perror("There was an error with read().");
			exit(1);
		}
	}
	if(-1 == close(fdout)) {
		perror("There was an error with close(). ");
		exit(1);
	}
	if(-1 == close(fdin)) {
		perror("There was an error with close(). ");
		exit(1);
	}
}

void rdwr(char* infile, char* outfile) {
	int fdin;
	int fdout;
	if(-1 == (fdin = open(infile, O_RDONLY))) {
		perror("There was an error with open(). ");
		exit(1);
	}
	if(-1 == (fdout = open(outfile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR))) {
		perror("There was an error with open(). ");
		exit(1);
	}
	char c[1];
	int size;
	if(-1 == (size = read(fdin, c, sizeof(c)))) {
		perror("There was an error with read().");
		exit(1);
	}
	while(size > 0) {
		if(-1 == write(fdout, c, size)) {
			perror("There was an error with write(). ");
			exit(1);
		}
		if(-1 == (size = read(fdin, c, sizeof(c)))) {
			perror("There was an error with read().");
			exit(1);
		}
	}
	if(-1 == close(fdout)) {
		perror("There was an error with close(). ");
		exit(1);
	}
	if(-1 == close(fdin)) {
		perror("There was an error with close(). ");
		exit(1);
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/os.h"

#include <time.h>

#include "platform/assert.h"

namespace dart {

bool OS::BreakDownSecondsSinceEpoch(time_t seconds_since_epoch,
                                    bool in_utc,
                                    BrokenDownDate* result) {
  struct tm tm_result;
  errno_t error_code;
  if (in_utc) {
    error_code = gmtime_s(&tm_result, &seconds_since_epoch);
  } else {
    // TODO(floitsch): we should be able to call tzset only once during
    // initialization.
    tzset();  // Make sure the libc knows about the local zone.
    error_code = localtime_s(&tm_result, &seconds_since_epoch);
  }
  result->year = tm_result.tm_year;
  result->month= tm_result.tm_mon;
  result->day = tm_result.tm_mday;
  result->hours = tm_result.tm_hour;
  result->minutes = tm_result.tm_min;
  result->seconds = tm_result.tm_sec;
  return error_code == 0;
}

bool OS::BrokenDownToSecondsSinceEpoch(
    const BrokenDownDate& broken_down, bool in_utc, time_t* result) {
  struct tm tm_broken_down;
  // mktime takes the years since 1900.
  tm_broken_down.tm_year = broken_down.year;
  tm_broken_down.tm_mon = broken_down.month;
  tm_broken_down.tm_mday = broken_down.day;
  tm_broken_down.tm_hour = broken_down.hours;
  tm_broken_down.tm_min = broken_down.minutes;
  tm_broken_down.tm_sec = broken_down.seconds;
  // Set wday to an impossible day, so that we can catch bad input.
  tm_broken_down.tm_wday = -1;
  // Make sure the libc knows about the local zone.
  // In case of 'in_utc' this call is mainly for multi-threading issues. If
  // another thread uses a time-function it will set the timezone. The timezone
  // adjustement below would then not work anymore.
  // TODO(floitsch): we should be able to call tzset only once during
  // initialization.
  tzset();
  if (in_utc) {
    // Disable daylight saving in utc mode.
    tm_broken_down.tm_isdst = 0;
    // mktime assumes that the given date is local time zone.
    *result = mktime(&tm_broken_down);
    // Remove the timezone.
    *result -= timezone;
  } else {
    // Let libc figure out if daylight saving is active.
    tm_broken_down.tm_isdst = -1;
    *result = mktime(&tm_broken_down);
  }
  if ((*result == -1) && (tm_broken_down.tm_wday == -1)) {
    return false;
  }
  return true;
}

int64_t OS::GetCurrentTimeMillis() {
  return GetCurrentTimeMicros() / 1000;
}

int64_t OS::GetCurrentTimeMicros() {
  static const int64_t kTimeEpoc = 116444736000000000LL;
  static const int64_t kTimeScaler = 10;  // 100 ns to us.

  // Although win32 uses 64-bit integers for representing timestamps,
  // these are packed into a FILETIME structure. The FILETIME
  // structure is just a struct representing a 64-bit integer. The
  // TimeStamp union allows access to both a FILETIME and an integer
  // representation of the timestamp. The Windows timestamp is in
  // 100-nanosecond intervals since January 1, 1601.
  union TimeStamp {
    FILETIME ft_;
    int64_t t_;
  };
  TimeStamp time;
  GetSystemTimeAsFileTime(&time.ft_);
  return (time.t_ - kTimeEpoc) / kTimeScaler;
}

word OS::ActivationFrameAlignment() {
#ifdef _WIN64
  // Windows 64-bit ABI requires the stack to be 16-byte aligned.
  return 16;
#else
  // No requirements on Win32.
  return 0;
#endif
}

word OS::PreferredCodeAlignment() {
  return 16;
}

uword OS::GetStackSizeLimit() {
  // TODO(ager): Can you programatically determine the actual stack
  // size limit on Windows? The 2MB limit is set at link time. Maybe
  // that value should be propagated here?
  return 2 * MB;
}

int OS::NumberOfAvailableProcessors() {
  SYSTEM_INFO info;
  GetSystemInfo(&info);
  return info.dwNumberOfProcessors;
}

void OS::Sleep(int64_t millis) {
  ::Sleep(millis);
}

void OS::DebugBreak() {
  __asm { int 3 }
}

void OS::Print(const char* format, ...) {
  va_list args;
  va_start(args, format);
  VFPrint(stdout, format, args);
  va_end(args);
}

void OS::VFPrint(FILE* stream, const char* format, va_list args) {
  vfprintf(stream, format, args);
  fflush(stream);
}

int OS::SNPrint(char* str, size_t size, const char* format, ...) {
  va_list args;
  va_start(args, format);
  int retval = VSNPrint(str, size, format, args);
  va_end(args);
  return retval;
}

int OS::VSNPrint(char* str, size_t size, const char* format, va_list args) {
  if (str == NULL || size == 0) {
    return _vscprintf(format, args);
  }
  int written =_vsnprintf(str, size, format, args);
  if (written < 0) {
    // _vsnprintf returns -1 if the number of characters to be written is
    // larger than 'size', so we call _vscprintf which returns the number
    // of characters that would have been written.
    written = _vscprintf(format, args);
  }
  // Make sure to zero-terminate the string if the output was
  // truncated or if there was an error.
  if (written >= size) {
    str[size - 1] = '\0';
  }
  return written;
}

void OS::PrintErr(const char* format, ...) {
  va_list args;
  va_start(args, format);
  VFPrint(stderr, format, args);
  va_end(args);
}

void OS::InitOnce() {
  // TODO(5411554): For now we check that initonce is called only once,
  // Once there is more formal mechanism to call InitOnce we can move
  // this check there.
  static bool init_once_called = false;
  ASSERT(init_once_called == false);
  init_once_called = true;
  // Do not pop up a message box when abort is called.
  _set_abort_behavior(0, _WRITE_ABORT_MSG);
}

void OS::Shutdown() {
}

void OS::Abort() {
  abort();
}

void OS::Exit(int code) {
  exit(code);
}

}  // namespace dart
<commit_msg>Address review comments. Review URL: https://chromiumcodereview.appspot.com//10052030<commit_after>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/os.h"

#include <time.h>

#include "platform/assert.h"

namespace dart {

bool OS::BreakDownSecondsSinceEpoch(time_t seconds_since_epoch,
                                    bool in_utc,
                                    BrokenDownDate* result) {
  struct tm tm_result;
  errno_t error_code;
  if (in_utc) {
    error_code = gmtime_s(&tm_result, &seconds_since_epoch);
  } else {
    // TODO(floitsch): we should be able to call tzset only once during
    // initialization.
    tzset();  // Make sure the libc knows about the local zone.
    error_code = localtime_s(&tm_result, &seconds_since_epoch);
  }
  result->year = tm_result.tm_year;
  result->month= tm_result.tm_mon;
  result->day = tm_result.tm_mday;
  result->hours = tm_result.tm_hour;
  result->minutes = tm_result.tm_min;
  result->seconds = tm_result.tm_sec;
  return error_code == 0;
}

bool OS::BrokenDownToSecondsSinceEpoch(
    const BrokenDownDate& broken_down, bool in_utc, time_t* result) {
  struct tm tm_broken_down;
  // mktime takes the years since 1900.
  tm_broken_down.tm_year = broken_down.year;
  tm_broken_down.tm_mon = broken_down.month;
  tm_broken_down.tm_mday = broken_down.day;
  tm_broken_down.tm_hour = broken_down.hours;
  tm_broken_down.tm_min = broken_down.minutes;
  tm_broken_down.tm_sec = broken_down.seconds;
  // Set wday to an impossible day, so that we can catch bad input.
  tm_broken_down.tm_wday = -1;
  // Make sure the libc knows about the local zone.
  // In case of 'in_utc' this call is mainly for multi-threading issues. If
  // another thread uses a time-function it will set the timezone. The timezone
  // adjustement below would then not work anymore.
  // TODO(floitsch): we should be able to call tzset only once during
  // initialization.
  tzset();
  if (in_utc) {
    // Disable daylight saving in utc mode.
    tm_broken_down.tm_isdst = 0;
    // mktime assumes that the given date is local time zone.
    *result = mktime(&tm_broken_down);
    // Remove the timezone.
    *result -= timezone;
  } else {
    // Let libc figure out if daylight saving is active.
    tm_broken_down.tm_isdst = -1;
    *result = mktime(&tm_broken_down);
  }
  if ((*result == -1) && (tm_broken_down.tm_wday == -1)) {
    return false;
  }
  return true;
}

int64_t OS::GetCurrentTimeMillis() {
  return GetCurrentTimeMicros() / 1000;
}

int64_t OS::GetCurrentTimeMicros() {
  static const int64_t kTimeEpoc = 116444736000000000LL;
  static const int64_t kTimeScaler = 10;  // 100 ns to us.

  // Although win32 uses 64-bit integers for representing timestamps,
  // these are packed into a FILETIME structure. The FILETIME
  // structure is just a struct representing a 64-bit integer. The
  // TimeStamp union allows access to both a FILETIME and an integer
  // representation of the timestamp. The Windows timestamp is in
  // 100-nanosecond intervals since January 1, 1601.
  union TimeStamp {
    FILETIME ft_;
    int64_t t_;
  };
  TimeStamp time;
  GetSystemTimeAsFileTime(&time.ft_);
  return (time.t_ - kTimeEpoc) / kTimeScaler;
}

word OS::ActivationFrameAlignment() {
#ifdef _WIN64
  // Windows 64-bit ABI requires the stack to be 16-byte aligned.
  return 16;
#else
  // No requirements on Win32.
  return 0;
#endif
}

word OS::PreferredCodeAlignment() {
  return 16;
}

uword OS::GetStackSizeLimit() {
  // TODO(ager): Can you programatically determine the actual stack
  // size limit on Windows? The 2MB limit is set at link time. Maybe
  // that value should be propagated here?
  return 2 * MB;
}

int OS::NumberOfAvailableProcessors() {
  SYSTEM_INFO info;
  GetSystemInfo(&info);
  return info.dwNumberOfProcessors;
}

void OS::Sleep(int64_t millis) {
  ::Sleep(millis);
}

void OS::DebugBreak() {
  __asm { int 3 }
}

void OS::Print(const char* format, ...) {
  va_list args;
  va_start(args, format);
  VFPrint(stdout, format, args);
  va_end(args);
}

void OS::VFPrint(FILE* stream, const char* format, va_list args) {
  vfprintf(stream, format, args);
  fflush(stream);
}

int OS::SNPrint(char* str, size_t size, const char* format, ...) {
  va_list args;
  va_start(args, format);
  int retval = VSNPrint(str, size, format, args);
  va_end(args);
  return retval;
}

// TODO(asiva): Consider moving this to "globals.h".
#ifndef va_copy
#define va_copy(dst, src) (memmove(&(dst), &(src), sizeof(dst)))
#endif  /* va_copy */

int OS::VSNPrint(char* str, size_t size, const char* format, va_list args) {
  if (str == NULL || size == 0) {
    return _vscprintf(format, args);
  }
  va_list args_copy;
  va_copy(args_copy, args);
  int written =_vsnprintf(str, size, format, args_copy);
  va_end(args_copy);
  if (written < 0) {
    // _vsnprintf returns -1 if the number of characters to be written is
    // larger than 'size', so we call _vscprintf which returns the number
    // of characters that would have been written.
    va_list args_retry;
    va_copy(args_retry, args);
    written = _vscprintf(format, args_retry);
    va_end(args_retry);
  }
  // Make sure to zero-terminate the string if the output was
  // truncated or if there was an error.
  if (written >= size) {
    str[size - 1] = '\0';
  }
  return written;
}

void OS::PrintErr(const char* format, ...) {
  va_list args;
  va_start(args, format);
  VFPrint(stderr, format, args);
  va_end(args);
}

void OS::InitOnce() {
  // TODO(5411554): For now we check that initonce is called only once,
  // Once there is more formal mechanism to call InitOnce we can move
  // this check there.
  static bool init_once_called = false;
  ASSERT(init_once_called == false);
  init_once_called = true;
  // Do not pop up a message box when abort is called.
  _set_abort_behavior(0, _WRITE_ABORT_MSG);
}

void OS::Shutdown() {
}

void OS::Abort() {
  abort();
}

void OS::Exit(int code) {
  exit(code);
}

}  // namespace dart
<|endoftext|>


<commit_before>#include <set>
#include <string>

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>

#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>

namespace asio = boost::asio;
namespace ip = asio::ip;
namespace placeholders = asio::placeholders;
namespace sys = boost::system;

class ConnectionManager;

class Connection
    : public boost::enable_shared_from_this< Connection >
{
public:

    typedef boost::shared_ptr< Connection > ConnectionPtr;

public:

    Connection(
        asio::io_service & ioService,
        ConnectionManager & connectionManager
    )
        : m_socket( ioService )
        , m_strand( ioService )
        , m_connectionManager( connectionManager )
    {
    }

    ~Connection()
    {
    }

    ip::tcp::socket & socket()
    {
        return m_socket;
    }

    void start()
    {
        auto const onDataRead = boost::bind(
            & Connection::onDataRead,
            shared_from_this(),
            placeholders::error,
            placeholders::bytes_transferred()
        );

        m_socket.async_read_some(
            asio::buffer( m_request, m_maxLength ),
            m_strand.wrap( onDataRead )
        );
    }

    void onDataRead(
        sys::error_code const & errorCode,
        std::size_t const bytesTransferred
    )
    {
        if( errorCode )
        {
            std::cerr << "Response Read Error: " << errorCode.message() << std::endl;
        }
        else
        {
            std::cout.write( m_request, bytesTransferred );
            std::cout << std::endl;

            broadcast( m_request, bytesTransferred );
        }
    }

    void broadcast(
        char const * const message,
        std::size_t const size
    );

    void onDataWritten(
        sys::error_code const & errorCode
    )
    {
        if( ! errorCode )
        {
            start();
        }
    }

    void onStop();

private:

    ip::tcp::socket m_socket;
    asio::io_service::strand m_strand;
    ConnectionManager & m_connectionManager;

    enum { m_maxLength = 1024 };
    char m_request[ m_maxLength ];
};

typedef Connection::ConnectionPtr ConnectionPtr;

class ConnectionManager
    : public boost::noncopyable
{
    typedef std::set< ConnectionPtr > ConnectionsPtr;

public:

    template< typename Function, class... Args >
    void forEach( Function&& func, Args && ...args )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        for( auto & connection : m_connections )
        {
            func( connection, std::forward< Args >( args )... );
        }
    }

    template< typename Predicate, typename Function, class... Args >
    void forEachIf( Predicate && predicate, Function && func, Args && ...args )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        for( auto & connection : m_connections )
        {
            if( predicate( connection ) )
            {
                func( connection, std::forward< Args >( args )... );
            }
        }
    }

    void add(
        ConnectionPtr & connection
    )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        m_connections.insert( connection );
    }

    void remove(
        ConnectionPtr const & connection
    )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        auto const pos = m_connections.find( connection );

        if( pos != m_connections.end() ){
            m_connections.erase( pos );
        }
    }

private:

    boost::mutex m_mutex;
    ConnectionsPtr m_connections;
};

void Connection::onStop()
{
    char const * const message = "Goodbye.";

    auto const onDataWritten = boost::bind(
        & Connection::onDataWritten,
        shared_from_this(),
        placeholders::error
    );

    asio::async_write(
        m_socket,
        asio::buffer( message, strlen( message ) ),
        onDataWritten
    );
}

void Connection::broadcast(
    char const * const message,
    std::size_t const size
)
{
    auto const skipSender = [ this ]( ConnectionPtr const & connectionPtr )
    {
        return connectionPtr->socket().native_handle() != this->socket().native_handle();
    };

    auto sendMessage = [ this, & size, & message ]( ConnectionPtr const & connectionPtr )
    {
        auto const onDataWritten = boost::bind(
            & Connection::onDataWritten,
            shared_from_this(),
            placeholders::error
        );

        asio::async_write(
            connectionPtr->socket(),
            asio::buffer( message, size ),
            onDataWritten
        );
    };

    m_connectionManager.forEachIf( skipSender, sendMessage );
}

class Server
{
public:

    Server(
        std::string const & port
    )
        : m_acceptor( m_ioService )
        , m_signals( m_ioService )
    {
        m_signals.add( SIGINT );
        m_signals.add( SIGTERM );
        m_signals.add( SIGQUIT );

        m_signals.async_wait(
            boost::bind( & Server::onStop, this )
        );

        ip::tcp::resolver resolver( m_ioService );
        ip::tcp::resolver::query query( "127.0.0.1", port );
        ip::tcp::endpoint endpoint = * resolver.resolve( query );

        m_acceptor.open( endpoint.protocol() );
        m_acceptor.set_option( ip::tcp::acceptor::reuse_address( true ) );
        m_acceptor.bind( endpoint );
        m_acceptor.listen();

        startAccept();
    }

    void run()
    {
        boost::thread_group threadGroup;

        auto const threadBody = boost::bind(
            & asio::io_service::run,
            & m_ioService
        );

        for( unsigned i = 0 ; i < 4 ; ++ i )
        {
            threadGroup.create_thread( threadBody );
        }

        threadGroup.join_all();
    }

private:

    void startAccept()
    {
        m_newConnection.reset( new Connection( m_ioService, m_connectionManager ) );

        m_connectionManager.add( m_newConnection );

        auto const onAccepted = boost::bind(
            & Server::onAccepted,
            this,
            placeholders::error
        );

        m_acceptor.async_accept(
            m_newConnection->socket(),
            onAccepted
        );
    }

    void onAccepted(
        sys::error_code const & errorCode
    )
    {
        if( ! errorCode )
        {
            m_newConnection->start();
        }

        startAccept();
    }

    void onStop()
    {
        m_connectionManager.forEach(
            boost::bind( & Connection::onStop, _1 )
        );

        m_ioService.stop();
    }

private:

    asio::io_service m_ioService;
    asio::ip::tcp::acceptor m_acceptor;
    asio::signal_set m_signals;

    ConnectionPtr m_newConnection;
    ConnectionManager m_connectionManager;
};

int main( int argc, char* argv[] )
{
    Server( argv[1] ).run();
}

<commit_msg>parse tribool<commit_after>#include <set>
#include <string>

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/logic/tribool.hpp>

#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>

namespace asio = boost::asio;
namespace ip = asio::ip;
namespace placeholders = asio::placeholders;
namespace sys = boost::system;

class ConnectionManager;

class Connection
    : public boost::enable_shared_from_this< Connection >
{
public:

    typedef boost::shared_ptr< Connection > ConnectionPtr;

public:

    Connection(
        asio::io_service & ioService,
        ConnectionManager & connectionManager
    )
        : m_socket( ioService )
        , m_strand( ioService )
        , m_connectionManager( connectionManager )
    {
    }

    ~Connection()
    {
    }

    ip::tcp::socket & socket()
    {
        return m_socket;
    }

    void start()
    {
        auto const onDataRead = boost::bind(
            & Connection::onDataRead,
            shared_from_this(),
            placeholders::error,
            placeholders::bytes_transferred()
        );

        m_socket.async_read_some(
            asio::buffer( m_request, m_maxLength ),
            m_strand.wrap( onDataRead )
        );
    }

    void processRequest(
        std::size_t const bytesTransferred
    )
    {
        broadcast( m_request, bytesTransferred );
    }

    void processParseError(
        std::size_t const bytesTransferred
    )
    {
        std::cerr
            << "Parse error: "
            << std::string( m_request, bytesTransferred )
            << std::endl;
    }

    boost::tribool parse(
        char const * const begin,
        char const * const end
    )
    {
        std::cout.write( begin, end - begin );
        std::cout << std::endl;

        return true;
    }

    void onDataRead(
        sys::error_code const & errorCode,
        std::size_t const bytesTransferred
    )
    {
        if( errorCode )
        {
            std::cerr << "Response Read Error: " << errorCode.message() << std::endl;
        }
        else
        {
            auto const result = parse( m_request, m_request + bytesTransferred );

            if( result )
            {
                processRequest( bytesTransferred );
            }
            else if( ! result )
            {
                processParseError( bytesTransferred );
            }
            else
            {
                auto const onDataRead = boost::bind(
                    & Connection::onDataRead,
                    shared_from_this(),
                    placeholders::error,
                    placeholders::bytes_transferred()
                );

                m_socket.async_read_some(
                    asio::buffer( m_request, m_maxLength ),
                    m_strand.wrap( onDataRead )
                );
            }
        }
    }

    void broadcast(
        char const * const message,
        std::size_t const size
    );

    void onDataWritten(
        sys::error_code const & errorCode
    )
    {
        if( ! errorCode )
        {
            start();
        }
    }

    void onStop();

private:

    ip::tcp::socket m_socket;
    asio::io_service::strand m_strand;
    ConnectionManager & m_connectionManager;

    enum { m_maxLength = 1024 };
    char m_request[ m_maxLength ];
};

typedef Connection::ConnectionPtr ConnectionPtr;

class ConnectionManager
    : public boost::noncopyable
{
    typedef std::set< ConnectionPtr > ConnectionsPtr;

public:

    template< typename Function, class... Args >
    void forEach( Function&& func, Args && ...args )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        for( auto & connection : m_connections )
        {
            func( connection, std::forward< Args >( args )... );
        }
    }

    template< typename Predicate, typename Function, class... Args >
    void forEachIf( Predicate && predicate, Function && func, Args && ...args )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        for( auto & connection : m_connections )
        {
            if( predicate( connection ) )
            {
                func( connection, std::forward< Args >( args )... );
            }
        }
    }

    void add(
        ConnectionPtr & connection
    )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        m_connections.insert( connection );
    }

    void remove(
        ConnectionPtr const & connection
    )
    {
        boost::lock_guard< boost::mutex > lock( m_mutex );

        auto const pos = m_connections.find( connection );

        if( pos != m_connections.end() ){
            m_connections.erase( pos );
        }
    }

private:

    boost::mutex m_mutex;
    ConnectionsPtr m_connections;
};

void Connection::onStop()
{
    char const * const message = "Goodbye.";

    auto const onDataWritten = boost::bind(
        & Connection::onDataWritten,
        shared_from_this(),
        placeholders::error
    );

    asio::async_write(
        m_socket,
        asio::buffer( message, strlen( message ) ),
        onDataWritten
    );
}

void Connection::broadcast(
    char const * const message,
    std::size_t const size
)
{
    auto const skipSender = [ this ]( ConnectionPtr const & connectionPtr )
    {
        return connectionPtr->socket().native_handle() != this->socket().native_handle();
    };

    auto sendMessage = [ this, & size, & message ]( ConnectionPtr const & connectionPtr )
    {
        auto const onDataWritten = boost::bind(
            & Connection::onDataWritten,
            shared_from_this(),
            placeholders::error
        );

        asio::async_write(
            connectionPtr->socket(),
            asio::buffer( message, size ),
            onDataWritten
        );
    };

    m_connectionManager.forEachIf( skipSender, sendMessage );
}

class Server
{
public:

    Server(
        std::string const & port
    )
        : m_acceptor( m_ioService )
        , m_signals( m_ioService )
    {
        m_signals.add( SIGINT );
        m_signals.add( SIGTERM );
        m_signals.add( SIGQUIT );

        m_signals.async_wait(
            boost::bind( & Server::onStop, this )
        );

        ip::tcp::resolver resolver( m_ioService );
        ip::tcp::resolver::query query( "127.0.0.1", port );
        ip::tcp::endpoint endpoint = * resolver.resolve( query );

        m_acceptor.open( endpoint.protocol() );
        m_acceptor.set_option( ip::tcp::acceptor::reuse_address( true ) );
        m_acceptor.bind( endpoint );
        m_acceptor.listen();

        startAccept();
    }

    void run()
    {
        boost::thread_group threadGroup;

        auto const threadBody = boost::bind(
            & asio::io_service::run,
            & m_ioService
        );

        for( unsigned i = 0 ; i < 4 ; ++ i )
        {
            threadGroup.create_thread( threadBody );
        }

        threadGroup.join_all();
    }

private:

    void startAccept()
    {
        m_newConnection.reset( new Connection( m_ioService, m_connectionManager ) );

        m_connectionManager.add( m_newConnection );

        auto const onAccepted = boost::bind(
            & Server::onAccepted,
            this,
            placeholders::error
        );

        m_acceptor.async_accept(
            m_newConnection->socket(),
            onAccepted
        );
    }

    void onAccepted(
        sys::error_code const & errorCode
    )
    {
        if( ! errorCode )
        {
            m_newConnection->start();
        }

        startAccept();
    }

    void onStop()
    {
        m_connectionManager.forEach(
            boost::bind( & Connection::onStop, _1 )
        );

        m_ioService.stop();
    }

private:

    asio::io_service m_ioService;
    asio::ip::tcp::acceptor m_acceptor;
    asio::signal_set m_signals;

    ConnectionPtr m_newConnection;
    ConnectionManager m_connectionManager;
};

int main( int argc, char* argv[] )
{
    Server( argv[1] ).run();
}

<|endoftext|>