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

  Program:   Visualization Toolkit
  Module:    vtkJPEGReader.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include "vtkJPEGReader.h"
#include "vtkObjectFactory.h"

extern "C" {
#include <jpeglib.h>
#include <setjmp.h>
}

vtkCxxRevisionMacro(vtkJPEGReader, "1.4");
vtkStandardNewMacro(vtkJPEGReader);

void vtkJPEGReader::ExecuteInformation()
{
  this->ComputeInternalFileName(this->DataExtent[4]);
  if (this->InternalFileName == NULL)
    {
    return;
    }

  FILE *fp = fopen(this->InternalFileName, "rb");
  if (!fp)
    {
    vtkErrorMacro("Unable to open file " << this->InternalFileName);
    return;
    }

  // create jpeg decompression object and error handler
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;

  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);

  // set the source file
  jpeg_stdio_src(&cinfo, fp);

  // read the header
  jpeg_read_header(&cinfo, TRUE);

  // force the output image size to be calculated (we could have used
  // cinfo.image_height etc. but that would preclude using libjpeg's
  // ability to scale an image on input).
  jpeg_calc_output_dimensions(&cinfo);

  // pull out the width/height, etc.
  this->DataExtent[0] = 0;
  this->DataExtent[1] = cinfo.output_width - 1;
  this->DataExtent[2] = 0;
  this->DataExtent[3] = cinfo.output_height - 1;

  this->SetDataScalarTypeToUnsignedChar();
  this->SetNumberOfScalarComponents( cinfo.output_components );

  this->vtkImageReader2::ExecuteInformation();

  // close the file
  jpeg_destroy_decompress(&cinfo);
  fclose(fp);
}

template <class OT>
static void vtkJPEGReaderUpdate2(vtkJPEGReader *self, OT *outPtr,
                                int *outExt, int *outInc, long)
{
  unsigned int ui;
  int i;
  FILE *fp = fopen(self->GetInternalFileName(), "rb");
  if (!fp)
    {
    return;
    }

  // create jpeg decompression object and error handler
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;

  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);

  // set the source file
  jpeg_stdio_src(&cinfo, fp);

  // read the header
  jpeg_read_header(&cinfo, TRUE);

  // prepare to read the bulk data
  jpeg_start_decompress(&cinfo);

  int rowbytes = cinfo.output_components * cinfo.output_width;
  unsigned char *tempImage = new unsigned char [rowbytes*cinfo.output_height];
  JSAMPROW *row_pointers = new JSAMPROW [cinfo.output_height];
  for (ui = 0; ui < cinfo.output_height; ++ui)
    {
    row_pointers[ui] = tempImage + rowbytes*ui;
    }

  // read the bulk data
  unsigned int remainingRows = cinfo.output_height;
  while (cinfo.output_scanline < cinfo.output_height)
    {
    remainingRows = cinfo.output_height - cinfo.output_scanline;
    jpeg_read_scanlines(&cinfo, &row_pointers[cinfo.output_scanline],
                        remainingRows);
    }

  // finish the decompression step
  jpeg_finish_decompress(&cinfo);

  // destroy the decompression object
  jpeg_destroy_decompress(&cinfo);

  // copy the data into the outPtr
  OT *outPtr2;
  outPtr2 = outPtr;
  long outSize = cinfo.output_components*(outExt[1] - outExt[0] + 1);
  for (i = outExt[2]; i <= outExt[3]; ++i)
    {
    memcpy(outPtr2,
           row_pointers[cinfo.output_height - i - 1]
           + outExt[0]*cinfo.output_components,
           outSize);
    outPtr2 += outInc[1];
    }
  delete [] tempImage;
  delete [] row_pointers;

  // close the file
  fclose(fp);
}

//----------------------------------------------------------------------------
// This function reads in one data of data.
// templated to handle different data types.
template <class OT>
static void vtkJPEGReaderUpdate(vtkJPEGReader *self, vtkImageData *data,
                               OT *outPtr)
{
  int outIncr[3];
  int outExtent[6];
  OT *outPtr2;

  data->GetExtent(outExtent);
  data->GetIncrements(outIncr);

  long pixSize = data->GetNumberOfScalarComponents()*sizeof(OT);

  outPtr2 = outPtr;
  int idx2;
  for (idx2 = outExtent[4]; idx2 <= outExtent[5]; ++idx2)
    {
    self->ComputeInternalFileName(idx2);
    // read in a JPEG file
    vtkJPEGReaderUpdate2(self, outPtr2, outExtent, outIncr, pixSize);
    self->UpdateProgress((idx2 - outExtent[4])/
                         (outExtent[5] - outExtent[4] + 1.0));
    outPtr2 += outIncr[2];
    }
}

//----------------------------------------------------------------------------
// This function reads a data from a file.  The datas extent/axes
// are assumed to be the same as the file extent/order.
void vtkJPEGReader::ExecuteData(vtkDataObject *output)
{
  vtkImageData *data = this->AllocateOutputData(output);

  if (this->InternalFileName == NULL)
    {
    vtkErrorMacro(<< "Either a FileName or FilePrefix must be specified.");
    return;
    }

  this->ComputeDataIncrements();

  // Call the correct templated function for the output
  void *outPtr;

  // Call the correct templated function for the input
  outPtr = data->GetScalarPointer();
  switch (data->GetScalarType())
    {
    vtkTemplateMacro3(vtkJPEGReaderUpdate, this, data, (VTK_TT *)(outPtr));
    default:
      vtkErrorMacro(<< "UpdateFromFile: Unknown data type");
    }
}

// create an error handler for jpeg that
// can longjmp out of the jpeg library
struct my_error_mgr
{
  struct jpeg_error_mgr pub;    /* "public" fields */
  jmp_buf setjmp_buffer;        /* for return to caller */
};

typedef struct my_error_mgr * my_error_ptr;
/*
 * Here's the routine that will replace the standard error_exit method:
 */

METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
  my_error_ptr myerr = (my_error_ptr) cinfo->err;

  /* Return control to the setjmp point */
  longjmp(myerr->setjmp_buffer, 1);
}

METHODDEF(void)
my_emit_message (j_common_ptr cinfo, int)
{
  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
  my_error_ptr myerr = (my_error_ptr) cinfo->err;

  /* Return control to the setjmp point */
  longjmp(myerr->setjmp_buffer, 1);
}

METHODDEF(void)
my_format_message (j_common_ptr cinfo, char*)
{
  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
  my_error_ptr myerr = (my_error_ptr) cinfo->err;

  /* Return control to the setjmp point */
  longjmp(myerr->setjmp_buffer, 1);
}

int vtkJPEGReader::CanReadFile(const char* fname)
{
  // open the file
  FILE *fp = fopen(fname, "rb");
  if (!fp)
    {
    return 0;
    }
  // read the first two bytes
  char magic[2];
  int n = fread(magic, sizeof(magic), 1, fp);
  if (n != sizeof(magic))
    {
    fclose(fp);
    return 0;
    }
  // check for the magic stuff:
  // 0xFF followed by 0xD8
  if( ( (magic[0] != char(0xFF)) || (magic[1] != char(0xD8)) ))
    {
    fclose(fp);
    return 0;
    }

  // magic number is ok, try and read the header
  struct my_error_mgr jerr;
  struct jpeg_decompress_struct cinfo;
  cinfo.err = jpeg_std_error(&jerr.pub);
  // for any error condition exit
  jerr.pub.error_exit = my_error_exit;
  jerr.pub.emit_message = my_emit_message;
  jerr.pub.output_message = my_error_exit;
  jerr.pub.format_message = my_format_message;
  if (setjmp(jerr.setjmp_buffer))
    {
    /* If we get here, the JPEG code has signaled an error.
     * We need to clean up the JPEG object, close the input file, and return.
     */
    jpeg_destroy_decompress(&cinfo);
    fclose(fp);
    return 0;
    }
  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress(&cinfo);
  /* Step 2: specify data source (eg, a file) */
  jpeg_stdio_src(&cinfo, fp);
  /* Step 3: read file parameters with jpeg_read_header() */
  jpeg_read_header(&cinfo, TRUE);

  // if no errors have occurred yet, then it must be jpeg
  jpeg_destroy_decompress(&cinfo);
  fclose(fp);
  return 1;
}
<commit_msg>better error checking<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkJPEGReader.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include "vtkJPEGReader.h"
#include "vtkObjectFactory.h"

extern "C" {
#include <jpeglib.h>
#include <setjmp.h>
}

vtkCxxRevisionMacro(vtkJPEGReader, "1.5");
vtkStandardNewMacro(vtkJPEGReader);

// create an error handler for jpeg that
// can longjmp out of the jpeg library
struct vtk_jpeg_error_mgr
{
  struct jpeg_error_mgr pub;    /* "public" fields */
  jmp_buf setjmp_buffer;        /* for return to caller */
  vtkJPEGReader* JPEGReader;
};

// this is called on jpeg error conditions
METHODDEF(void)
vtk_jpeg_error_exit (j_common_ptr cinfo)
{
  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
  vtk_jpeg_error_mgr * err = reinterpret_cast<vtk_jpeg_error_mgr*>(cinfo->err);

  /* Return control to the setjmp point */
  longjmp(err->setjmp_buffer, 1);
}

METHODDEF(void)
vtk_jpeg_output_message (j_common_ptr cinfo)
{
  char buffer[JMSG_LENGTH_MAX];

  /* Create the message */
  (*cinfo->err->format_message) (cinfo, buffer);
  vtk_jpeg_error_mgr * err = reinterpret_cast<vtk_jpeg_error_mgr*>(cinfo->err);
  vtkWarningWithObjectMacro(err->JPEGReader,
                            "libjpeg error: " <<  buffer);
}

void vtkJPEGReader::ExecuteInformation()
{
  this->ComputeInternalFileName(this->DataExtent[4]);
  if (this->InternalFileName == NULL)
    {
    return;
    }

  FILE *fp = fopen(this->InternalFileName, "rb");
  if (!fp)
    {
    vtkErrorWithObjectMacro(this,
                            "Unable to open file "
                            << this->InternalFileName);
    return;
    }

  // create jpeg decompression object and error handler
  struct jpeg_decompress_struct cinfo;
  struct vtk_jpeg_error_mgr jerr;
  jerr.JPEGReader = this;

  cinfo.err = jpeg_std_error(&jerr.pub);
  // for any jpeg error call vtk_jpeg_error_exit
  jerr.pub.error_exit = vtk_jpeg_error_exit;
  // for any output message call vtk_jpeg_output_message
  jerr.pub.output_message = vtk_jpeg_output_message;
  if (setjmp(jerr.setjmp_buffer))
    {
    // clean up
    jpeg_destroy_decompress(&cinfo);
    // close the file
    fclose(fp);
    // this is not a valid jpeg file
    vtkErrorWithObjectMacro(this, "libjpeg could not read file: "
                            << this->InternalFileName);
    return;
    }
  jpeg_create_decompress(&cinfo);

  // set the source file
  jpeg_stdio_src(&cinfo, fp);

  // read the header
  jpeg_read_header(&cinfo, TRUE);

  // force the output image size to be calculated (we could have used
  // cinfo.image_height etc. but that would preclude using libjpeg's
  // ability to scale an image on input).
  jpeg_calc_output_dimensions(&cinfo);

  // pull out the width/height, etc.
  this->DataExtent[0] = 0;
  this->DataExtent[1] = cinfo.output_width - 1;
  this->DataExtent[2] = 0;
  this->DataExtent[3] = cinfo.output_height - 1;

  this->SetDataScalarTypeToUnsignedChar();
  this->SetNumberOfScalarComponents( cinfo.output_components );

  this->vtkImageReader2::ExecuteInformation();

  // close the file
  jpeg_destroy_decompress(&cinfo);
  fclose(fp);
}

template <class OT>
static void vtkJPEGReaderUpdate2(vtkJPEGReader *self, OT *outPtr,
                                int *outExt, int *outInc, long)
{
  unsigned int ui;
  int i;
  FILE *fp = fopen(self->GetInternalFileName(), "rb");
  if (!fp)
    {
    return;
    }

  // create jpeg decompression object and error handler
  struct jpeg_decompress_struct cinfo;
  struct vtk_jpeg_error_mgr jerr;
  jerr.JPEGReader = self;

  cinfo.err = jpeg_std_error(&jerr.pub);
  // for any jpeg error call vtk_jpeg_error_exit
  jerr.pub.error_exit = vtk_jpeg_error_exit;
  // for any output message call vtk_jpeg_output_message
  jerr.pub.output_message = vtk_jpeg_output_message;
  if (setjmp(jerr.setjmp_buffer))
    {
    // clean up
    jpeg_destroy_decompress(&cinfo);
    // close the file
    fclose(fp);
    vtkErrorWithObjectMacro(self, "libjpeg could not read file: "
                            << self->GetInternalFileName());
    // this is not a valid jpeg file
    return;
    }
  jpeg_create_decompress(&cinfo);

  // set the source file
  jpeg_stdio_src(&cinfo, fp);

  // read the header
  jpeg_read_header(&cinfo, TRUE);

  // prepare to read the bulk data
  jpeg_start_decompress(&cinfo);

  int rowbytes = cinfo.output_components * cinfo.output_width;
  unsigned char *tempImage = new unsigned char [rowbytes*cinfo.output_height];
  JSAMPROW *row_pointers = new JSAMPROW [cinfo.output_height];
  for (ui = 0; ui < cinfo.output_height; ++ui)
    {
    row_pointers[ui] = tempImage + rowbytes*ui;
    }

  // read the bulk data
  unsigned int remainingRows = cinfo.output_height;
  while (cinfo.output_scanline < cinfo.output_height)
    {
    remainingRows = cinfo.output_height - cinfo.output_scanline;
    jpeg_read_scanlines(&cinfo, &row_pointers[cinfo.output_scanline],
                        remainingRows);
    }

  // finish the decompression step
  jpeg_finish_decompress(&cinfo);

  // destroy the decompression object
  jpeg_destroy_decompress(&cinfo);

  // copy the data into the outPtr
  OT *outPtr2;
  outPtr2 = outPtr;
  long outSize = cinfo.output_components*(outExt[1] - outExt[0] + 1);
  for (i = outExt[2]; i <= outExt[3]; ++i)
    {
    memcpy(outPtr2,
           row_pointers[cinfo.output_height - i - 1]
           + outExt[0]*cinfo.output_components,
           outSize);
    outPtr2 += outInc[1];
    }
  delete [] tempImage;
  delete [] row_pointers;

  // close the file
  fclose(fp);
}

//----------------------------------------------------------------------------
// This function reads in one data of data.
// templated to handle different data types.
template <class OT>
static void vtkJPEGReaderUpdate(vtkJPEGReader *self, vtkImageData *data,
                               OT *outPtr)
{
  int outIncr[3];
  int outExtent[6];
  OT *outPtr2;

  data->GetExtent(outExtent);
  data->GetIncrements(outIncr);

  long pixSize = data->GetNumberOfScalarComponents()*sizeof(OT);

  outPtr2 = outPtr;
  int idx2;
  for (idx2 = outExtent[4]; idx2 <= outExtent[5]; ++idx2)
    {
    self->ComputeInternalFileName(idx2);
    // read in a JPEG file
    vtkJPEGReaderUpdate2(self, outPtr2, outExtent, outIncr, pixSize);
    self->UpdateProgress((idx2 - outExtent[4])/
                         (outExtent[5] - outExtent[4] + 1.0));
    outPtr2 += outIncr[2];
    }
}

//----------------------------------------------------------------------------
// This function reads a data from a file.  The datas extent/axes
// are assumed to be the same as the file extent/order.
void vtkJPEGReader::ExecuteData(vtkDataObject *output)
{
  vtkImageData *data = this->AllocateOutputData(output);

  if (this->InternalFileName == NULL)
    {
    vtkErrorMacro(<< "Either a FileName or FilePrefix must be specified.");
    return;
    }

  this->ComputeDataIncrements();

  // Call the correct templated function for the output
  void *outPtr;

  // Call the correct templated function for the input
  outPtr = data->GetScalarPointer();
  switch (data->GetScalarType())
    {
    vtkTemplateMacro3(vtkJPEGReaderUpdate, this, data, (VTK_TT *)(outPtr));
    default:
      vtkErrorMacro(<< "UpdateFromFile: Unknown data type");
    }
}

int vtkJPEGReader::CanReadFile(const char* fname)
{
  // open the file
  FILE *fp = fopen(fname, "rb");
  if (!fp)
    {
    return 0;
    }
  // read the first two bytes
  char magic[2];
  int n = fread(magic, sizeof(magic), 1, fp);
  if (n != 1)
    {
    fclose(fp);
    return 0;
    }
  // check for the magic stuff:
  // 0xFF followed by 0xD8
  if( ( (magic[0] != char(0xFF)) || (magic[1] != char(0xD8)) ))
    {
    fclose(fp);
    return 0;
    }
  // go back to the start of the file
  fseek(fp, 0, SEEK_SET);
  // magic number is ok, try and read the header
  struct vtk_jpeg_error_mgr jerr;
  jerr.JPEGReader = this;
  struct jpeg_decompress_struct cinfo;
  cinfo.err = jpeg_std_error(&jerr.pub);
  // for any jpeg error call vtk_jpeg_error_exit
  jerr.pub.error_exit = vtk_jpeg_error_exit;
  // for any output message call vtk_jpeg_error_exit
  jerr.pub.output_message = vtk_jpeg_error_exit;
  // set the jump point, if there is a jpeg error or warning
  // this will evaluate to true
  if (setjmp(jerr.setjmp_buffer))
    {
    // clean up
    jpeg_destroy_decompress(&cinfo);
    // close the file
    fclose(fp);
    // this is not a valid jpeg file
    return 0;
    }
  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress(&cinfo);
  /* Step 2: specify data source (eg, a file) */
  jpeg_stdio_src(&cinfo, fp);
  /* Step 3: read file parameters with jpeg_read_header() */
  jpeg_read_header(&cinfo, TRUE);

  // if no errors have occurred yet, then it must be jpeg
  jpeg_destroy_decompress(&cinfo);
  fclose(fp);
  return 1;
}
<|endoftext|>


<commit_before>
/*
 * Copyright 2009 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkColorTable.h"
#include "SkFlattenableBuffers.h"
#include "SkStream.h"
#include "SkTemplates.h"

SK_DEFINE_INST_COUNT(SkColorTable)

SkColorTable::SkColorTable(int count)
    : f16BitCache(NULL), fFlags(0)
{
    if (count < 0)
        count = 0;
    else if (count > 256)
        count = 256;

    fCount = SkToU16(count);
    fColors = (SkPMColor*)sk_malloc_throw(count * sizeof(SkPMColor));
    memset(fColors, 0, count * sizeof(SkPMColor));

    SkDEBUGCODE(fColorLockCount = 0;)
    SkDEBUGCODE(f16BitCacheLockCount = 0;)
}

// As copy constructor is hidden in the class hierarchy, we need to call
// default constructor explicitly to suppress a compiler warning.
SkColorTable::SkColorTable(const SkColorTable& src) : INHERITED() {
    f16BitCache = NULL;
    fFlags = src.fFlags;
    int count = src.count();
    fCount = SkToU16(count);
    fColors = reinterpret_cast<SkPMColor*>(
                                    sk_malloc_throw(count * sizeof(SkPMColor)));
    memcpy(fColors, src.fColors, count * sizeof(SkPMColor));

    SkDEBUGCODE(fColorLockCount = 0;)
    SkDEBUGCODE(f16BitCacheLockCount = 0;)
}

SkColorTable::SkColorTable(const SkPMColor colors[], int count)
    : f16BitCache(NULL), fFlags(0)
{
    if (count < 0)
        count = 0;
    else if (count > 256)
        count = 256;

    fCount = SkToU16(count);
    fColors = reinterpret_cast<SkPMColor*>(
                                    sk_malloc_throw(count * sizeof(SkPMColor)));

    if (colors)
        memcpy(fColors, colors, count * sizeof(SkPMColor));

    SkDEBUGCODE(fColorLockCount = 0;)
    SkDEBUGCODE(f16BitCacheLockCount = 0;)
}

SkColorTable::~SkColorTable()
{
    SkASSERT(fColorLockCount == 0);
    SkASSERT(f16BitCacheLockCount == 0);

    sk_free(fColors);
    sk_free(f16BitCache);
}

void SkColorTable::setFlags(unsigned flags)
{
    fFlags = SkToU8(flags);
}

void SkColorTable::unlockColors(bool changed)
{
    SkASSERT(fColorLockCount != 0);
    SkDEBUGCODE(sk_atomic_dec(&fColorLockCount);)
    if (changed)
        this->inval16BitCache();
}

void SkColorTable::inval16BitCache()
{
    SkASSERT(f16BitCacheLockCount == 0);
    if (f16BitCache)
    {
        sk_free(f16BitCache);
        f16BitCache = NULL;
    }
}

#include "SkColorPriv.h"

static inline void build_16bitcache(uint16_t dst[], const SkPMColor src[], int count)
{
    while (--count >= 0)
        *dst++ = SkPixel32ToPixel16_ToU16(*src++);
}

const uint16_t* SkColorTable::lock16BitCache()
{
    if (fFlags & kColorsAreOpaque_Flag)
    {
        if (f16BitCache == NULL) // build the cache
        {
            f16BitCache = (uint16_t*)sk_malloc_throw(fCount * sizeof(uint16_t));
            build_16bitcache(f16BitCache, fColors, fCount);
        }
    }
    else    // our colors have alpha, so no cache
    {
        this->inval16BitCache();
        if (f16BitCache)
        {
            sk_free(f16BitCache);
            f16BitCache = NULL;
        }
    }

    SkDEBUGCODE(f16BitCacheLockCount += 1);
    return f16BitCache;
}

void SkColorTable::setIsOpaque(bool isOpaque) {
    if (isOpaque) {
        fFlags |= kColorsAreOpaque_Flag;
    } else {
        fFlags &= ~kColorsAreOpaque_Flag;
    }
}

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

SkColorTable::SkColorTable(SkFlattenableReadBuffer& buffer) {
    f16BitCache = NULL;
    SkDEBUGCODE(fColorLockCount = 0;)
    SkDEBUGCODE(f16BitCacheLockCount = 0;)

    fFlags = buffer.readUInt();
    fCount = buffer.getArrayCount();
    fColors = (SkPMColor*)sk_malloc_throw(fCount * sizeof(SkPMColor));
    const uint32_t countRead = buffer.readColorArray(fColors);
    SkASSERT((unsigned)fCount <= 256);
    SkASSERT(countRead == fCount);
}

void SkColorTable::flatten(SkFlattenableWriteBuffer& buffer) const {
    buffer.writeUInt(fFlags);
    buffer.writeColorArray(fColors, fCount);
}
<commit_msg>Fix warning-as-error for var used only in an assert (and therefore not in the release build).<commit_after>
/*
 * Copyright 2009 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkColorTable.h"
#include "SkFlattenableBuffers.h"
#include "SkStream.h"
#include "SkTemplates.h"

SK_DEFINE_INST_COUNT(SkColorTable)

SkColorTable::SkColorTable(int count)
    : f16BitCache(NULL), fFlags(0)
{
    if (count < 0)
        count = 0;
    else if (count > 256)
        count = 256;

    fCount = SkToU16(count);
    fColors = (SkPMColor*)sk_malloc_throw(count * sizeof(SkPMColor));
    memset(fColors, 0, count * sizeof(SkPMColor));

    SkDEBUGCODE(fColorLockCount = 0;)
    SkDEBUGCODE(f16BitCacheLockCount = 0;)
}

// As copy constructor is hidden in the class hierarchy, we need to call
// default constructor explicitly to suppress a compiler warning.
SkColorTable::SkColorTable(const SkColorTable& src) : INHERITED() {
    f16BitCache = NULL;
    fFlags = src.fFlags;
    int count = src.count();
    fCount = SkToU16(count);
    fColors = reinterpret_cast<SkPMColor*>(
                                    sk_malloc_throw(count * sizeof(SkPMColor)));
    memcpy(fColors, src.fColors, count * sizeof(SkPMColor));

    SkDEBUGCODE(fColorLockCount = 0;)
    SkDEBUGCODE(f16BitCacheLockCount = 0;)
}

SkColorTable::SkColorTable(const SkPMColor colors[], int count)
    : f16BitCache(NULL), fFlags(0)
{
    if (count < 0)
        count = 0;
    else if (count > 256)
        count = 256;

    fCount = SkToU16(count);
    fColors = reinterpret_cast<SkPMColor*>(
                                    sk_malloc_throw(count * sizeof(SkPMColor)));

    if (colors)
        memcpy(fColors, colors, count * sizeof(SkPMColor));

    SkDEBUGCODE(fColorLockCount = 0;)
    SkDEBUGCODE(f16BitCacheLockCount = 0;)
}

SkColorTable::~SkColorTable()
{
    SkASSERT(fColorLockCount == 0);
    SkASSERT(f16BitCacheLockCount == 0);

    sk_free(fColors);
    sk_free(f16BitCache);
}

void SkColorTable::setFlags(unsigned flags)
{
    fFlags = SkToU8(flags);
}

void SkColorTable::unlockColors(bool changed)
{
    SkASSERT(fColorLockCount != 0);
    SkDEBUGCODE(sk_atomic_dec(&fColorLockCount);)
    if (changed)
        this->inval16BitCache();
}

void SkColorTable::inval16BitCache()
{
    SkASSERT(f16BitCacheLockCount == 0);
    if (f16BitCache)
    {
        sk_free(f16BitCache);
        f16BitCache = NULL;
    }
}

#include "SkColorPriv.h"

static inline void build_16bitcache(uint16_t dst[], const SkPMColor src[], int count)
{
    while (--count >= 0)
        *dst++ = SkPixel32ToPixel16_ToU16(*src++);
}

const uint16_t* SkColorTable::lock16BitCache()
{
    if (fFlags & kColorsAreOpaque_Flag)
    {
        if (f16BitCache == NULL) // build the cache
        {
            f16BitCache = (uint16_t*)sk_malloc_throw(fCount * sizeof(uint16_t));
            build_16bitcache(f16BitCache, fColors, fCount);
        }
    }
    else    // our colors have alpha, so no cache
    {
        this->inval16BitCache();
        if (f16BitCache)
        {
            sk_free(f16BitCache);
            f16BitCache = NULL;
        }
    }

    SkDEBUGCODE(f16BitCacheLockCount += 1);
    return f16BitCache;
}

void SkColorTable::setIsOpaque(bool isOpaque) {
    if (isOpaque) {
        fFlags |= kColorsAreOpaque_Flag;
    } else {
        fFlags &= ~kColorsAreOpaque_Flag;
    }
}

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

SkColorTable::SkColorTable(SkFlattenableReadBuffer& buffer) {
    f16BitCache = NULL;
    SkDEBUGCODE(fColorLockCount = 0;)
    SkDEBUGCODE(f16BitCacheLockCount = 0;)

    fFlags = buffer.readUInt();
    fCount = buffer.getArrayCount();
    fColors = (SkPMColor*)sk_malloc_throw(fCount * sizeof(SkPMColor));
    SkDEBUGCODE(const uint32_t countRead =) buffer.readColorArray(fColors);
#ifdef SK_DEBUG
    SkASSERT((unsigned)fCount <= 256);
    SkASSERT(countRead == fCount);
#endif
}

void SkColorTable::flatten(SkFlattenableWriteBuffer& buffer) const {
    buffer.writeUInt(fFlags);
    buffer.writeColorArray(fColors, fCount);
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2014, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "src/cpp/client/channel.h"

#include <chrono>
#include <memory>

#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>

#include "src/cpp/proto/proto_utils.h"
#include <grpc++/channel_arguments.h>
#include <grpc++/client_context.h>
#include <grpc++/completion_queue.h>
#include <grpc++/config.h>
#include <grpc++/credentials.h>
#include <grpc++/impl/call.h>
#include <grpc++/impl/rpc_method.h>
#include <grpc++/status.h>
#include <google/protobuf/message.h>

namespace grpc {

Channel::Channel(const grpc::string &target, const ChannelArguments &args)
    : target_(target) {
  grpc_channel_args channel_args;
  args.SetChannelArgs(&channel_args);
  c_channel_ = grpc_channel_create(
      target_.c_str(), channel_args.num_args > 0 ? &channel_args : nullptr);
}

Channel::Channel(const grpc::string &target,
                 const std::unique_ptr<Credentials> &creds,
                 const ChannelArguments &args)
    : target_(args.GetSslTargetNameOverride().empty()
                  ? target
                  : args.GetSslTargetNameOverride()) {
  grpc_channel_args channel_args;
  args.SetChannelArgs(&channel_args);
  grpc_credentials *c_creds = creds ? creds->GetRawCreds() : nullptr;
  c_channel_ = grpc_secure_channel_create(
      c_creds, target.c_str(),
      channel_args.num_args > 0 ? &channel_args : nullptr);
}

Channel::~Channel() { grpc_channel_destroy(c_channel_); }

Call Channel::CreateCall(const RpcMethod &method, ClientContext *context,
                         CompletionQueue *cq) {
  auto c_call =
      grpc_channel_create_call(
          c_channel_, cq->cq(), method.name(),
          context->authority().empty() ?  target_.c_str()
                                       : context->authority(),
          context->RawDeadline());
  context->set_call(c_call);
  return Call(c_call, this, cq);
}

void Channel::PerformOpsOnCall(CallOpBuffer *buf, Call *call) {
  static const size_t MAX_OPS = 8;
  size_t nops = MAX_OPS;
  grpc_op ops[MAX_OPS];
  buf->FillOps(ops, &nops);
  GPR_ASSERT(GRPC_CALL_OK ==
             grpc_call_start_batch(call->call(), ops, nops, buf));
}

}  // namespace grpc
<commit_msg>should use c_str<commit_after>/*
 *
 * Copyright 2014, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "src/cpp/client/channel.h"

#include <chrono>
#include <memory>

#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>

#include "src/cpp/proto/proto_utils.h"
#include <grpc++/channel_arguments.h>
#include <grpc++/client_context.h>
#include <grpc++/completion_queue.h>
#include <grpc++/config.h>
#include <grpc++/credentials.h>
#include <grpc++/impl/call.h>
#include <grpc++/impl/rpc_method.h>
#include <grpc++/status.h>
#include <google/protobuf/message.h>

namespace grpc {

Channel::Channel(const grpc::string &target, const ChannelArguments &args)
    : target_(target) {
  grpc_channel_args channel_args;
  args.SetChannelArgs(&channel_args);
  c_channel_ = grpc_channel_create(
      target_.c_str(), channel_args.num_args > 0 ? &channel_args : nullptr);
}

Channel::Channel(const grpc::string &target,
                 const std::unique_ptr<Credentials> &creds,
                 const ChannelArguments &args)
    : target_(args.GetSslTargetNameOverride().empty()
                  ? target
                  : args.GetSslTargetNameOverride()) {
  grpc_channel_args channel_args;
  args.SetChannelArgs(&channel_args);
  grpc_credentials *c_creds = creds ? creds->GetRawCreds() : nullptr;
  c_channel_ = grpc_secure_channel_create(
      c_creds, target.c_str(),
      channel_args.num_args > 0 ? &channel_args : nullptr);
}

Channel::~Channel() { grpc_channel_destroy(c_channel_); }

Call Channel::CreateCall(const RpcMethod &method, ClientContext *context,
                         CompletionQueue *cq) {
  auto c_call =
      grpc_channel_create_call(
          c_channel_, cq->cq(), method.name(),
          context->authority().empty() ?  target_.c_str()
                                       : context->authority().c_str(),
          context->RawDeadline());
  context->set_call(c_call);
  return Call(c_call, this, cq);
}

void Channel::PerformOpsOnCall(CallOpBuffer *buf, Call *call) {
  static const size_t MAX_OPS = 8;
  size_t nops = MAX_OPS;
  grpc_op ops[MAX_OPS];
  buf->FillOps(ops, &nops);
  GPR_ASSERT(GRPC_CALL_OK ==
             grpc_call_start_batch(call->call(), ops, nops, buf));
}

}  // namespace grpc
<|endoftext|>


<commit_before>/*
 * FileLock.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/FileLock.hpp>

// #define RSTUDIO_ENABLE_DEBUG_MACROS
#include <core/Macros.hpp>

#include <core/Settings.hpp>
#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/FileSerializer.hpp>

#include <boost/algorithm/string.hpp>

namespace rstudio {
namespace core {

namespace file_lock {
void initialize()
{
   FileLock::initialize();
}
} // end namespace file_lock

namespace {

const char * const kLockTypeAdvisory  = "advisory";
const char * const kLockTypeLinkBased = "linkbased";

const char * const kLocksConfPath = "/etc/rstudio/file-locks";
#define kDefaultRefreshRate     20.0
#define kDefaultTimeoutInterval 30.0

std::string lockTypeToString(FileLock::LockType type)
{
   switch (type)
   {
   case FileLock::LOCKTYPE_ADVISORY:  return kLockTypeAdvisory;
   case FileLock::LOCKTYPE_LINKBASED: return kLockTypeLinkBased;
   }

   // not reached
   return std::string();
}

FileLock::LockType stringToLockType(const std::string& lockType)
{
   using namespace boost::algorithm;

   if (boost::iequals(lockType, kLockTypeAdvisory))
      return FileLock::LOCKTYPE_ADVISORY;
   else if (boost::iequals(lockType, kLockTypeLinkBased))
      return FileLock::LOCKTYPE_LINKBASED;

   LOG_WARNING_MESSAGE("unrecognized lock type '" + lockType + "'");
   return FileLock::LOCKTYPE_ADVISORY;
}

double getFieldPositive(const Settings& settings,
                        const std::string& name,
                        double defaultValue)
{
   double value = settings.getDouble(name, defaultValue);
   if (value < 0)
   {
      LOG_WARNING_MESSAGE("invalid field '" + name + "': must be positive");
      return defaultValue;
   }

   return value;
}

} // end anonymous namespace

bool s_isInitialized = false;

void FileLock::ensureInitialized()
{
   if (s_isInitialized)
      return;

   FileLock::initialize();
}

void FileLock::initialize(FilePath locksConfPath)
{
   s_isInitialized = true;

   if (locksConfPath.empty())
      locksConfPath = FilePath(kLocksConfPath);

   if (!locksConfPath.exists())
      return;

   Settings settings;
   Error error = settings.initialize(locksConfPath);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   FileLock::initialize(settings);
}

void FileLock::initialize(const Settings& settings)
{
   s_isInitialized = true;

   // default lock type
   FileLock::s_defaultType = stringToLockType(settings.get("lock-type", kLockTypeAdvisory));

   // timeout interval
   double timeoutInterval = getFieldPositive(settings, "timeout-interval", kDefaultTimeoutInterval);
   FileLock::s_timeoutInterval = boost::posix_time::seconds(timeoutInterval);

   // refresh rate
   double refreshRate = getFieldPositive(settings, "refresh-rate", kDefaultRefreshRate);
   FileLock::s_refreshRate = boost::posix_time::seconds(refreshRate);

   DEBUG_BLOCK("lock initialization")
   {
      std::cerr << "Type: "    << lockTypeToString(FileLock::s_defaultType) << std::endl;
      std::cerr << "Timeout: " << FileLock::s_timeoutInterval.total_seconds() << std::endl;
      std::cerr << "Refresh: " << FileLock::s_refreshRate.total_seconds() << std::endl;
   }
}

// default values for static members
FileLock::LockType FileLock::s_defaultType(FileLock::LOCKTYPE_ADVISORY);
boost::posix_time::seconds FileLock::s_timeoutInterval(kDefaultTimeoutInterval);
boost::posix_time::seconds FileLock::s_refreshRate(kDefaultRefreshRate);

boost::shared_ptr<FileLock> FileLock::create(LockType type)
{
   switch (type)
   {
   case LOCKTYPE_ADVISORY:  return boost::shared_ptr<FileLock>(new AdvisoryFileLock());
   case LOCKTYPE_LINKBASED: return boost::shared_ptr<FileLock>(new LinkBasedFileLock());
   }

   // shouldn't be reached
   return boost::shared_ptr<FileLock>(new AdvisoryFileLock());
}

boost::shared_ptr<FileLock> FileLock::createDefault()
{
   return FileLock::create(s_defaultType);
}

void FileLock::refresh()
{
   AdvisoryFileLock::refresh();
   LinkBasedFileLock::refresh();
}

void FileLock::cleanUp()
{
   AdvisoryFileLock::cleanUp();
   LinkBasedFileLock::cleanUp();
}

namespace {

void schedulePeriodicExecution(
      const boost::system::error_code& ec,
      boost::asio::deadline_timer& timer,
      boost::posix_time::seconds interval,
      boost::function<void()> callback)
{
   try
   {
      // bail on boost errors (these are very unexpected)
      if (ec)
      {
         LOG_ERROR(core::Error(ec, ERROR_LOCATION));
         return;
      }

      // execute callback
      callback();

      // reschedule
      boost::system::error_code errc;
      timer.expires_at(timer.expires_at() + interval, errc);
      if (errc)
      {
         LOG_ERROR(Error(errc, ERROR_LOCATION));
         return;
      }

      timer.async_wait(boost::bind(
                          schedulePeriodicExecution,
                          boost::asio::placeholders::error,
                          boost::ref(timer),
                          interval,
                          callback));
   }
   catch (...)
   {
      // swallow errors
   }
}

} // end anonymous namespace

void FileLock::refreshPeriodically(boost::asio::io_service& service,
                                   boost::posix_time::seconds interval)
{
   // protect against re-entrancy
   static bool s_isRefreshing = false;
   if (s_isRefreshing)
      return;
   s_isRefreshing = true;

   static boost::asio::deadline_timer timer(service, interval);
   timer.async_wait(boost::bind(
                       schedulePeriodicExecution,
                       boost::asio::placeholders::error,
                       boost::ref(timer),
                       interval,
                       FileLock::refresh));
}

} // end namespace core
} // end namespace rstudio
<commit_msg>use double rather than macro for defaults<commit_after>/*
 * FileLock.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/FileLock.hpp>

// #define RSTUDIO_ENABLE_DEBUG_MACROS
#include <core/Macros.hpp>

#include <core/Settings.hpp>
#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/FileSerializer.hpp>

#include <boost/algorithm/string.hpp>

namespace rstudio {
namespace core {

namespace file_lock {
void initialize()
{
   FileLock::initialize();
}
} // end namespace file_lock

namespace {

const char * const kLockTypeAdvisory  = "advisory";
const char * const kLockTypeLinkBased = "linkbased";

const char * const kLocksConfPath    = "/etc/rstudio/file-locks";
const double kDefaultRefreshRate     = 20.0;
const double kDefaultTimeoutInterval = 30.0;

std::string lockTypeToString(FileLock::LockType type)
{
   switch (type)
   {
   case FileLock::LOCKTYPE_ADVISORY:  return kLockTypeAdvisory;
   case FileLock::LOCKTYPE_LINKBASED: return kLockTypeLinkBased;
   }

   // not reached
   return std::string();
}

FileLock::LockType stringToLockType(const std::string& lockType)
{
   using namespace boost::algorithm;

   if (boost::iequals(lockType, kLockTypeAdvisory))
      return FileLock::LOCKTYPE_ADVISORY;
   else if (boost::iequals(lockType, kLockTypeLinkBased))
      return FileLock::LOCKTYPE_LINKBASED;

   LOG_WARNING_MESSAGE("unrecognized lock type '" + lockType + "'");
   return FileLock::LOCKTYPE_ADVISORY;
}

double getFieldPositive(const Settings& settings,
                        const std::string& name,
                        double defaultValue)
{
   double value = settings.getDouble(name, defaultValue);
   if (value < 0)
   {
      LOG_WARNING_MESSAGE("invalid field '" + name + "': must be positive");
      return defaultValue;
   }

   return value;
}

} // end anonymous namespace

bool s_isInitialized = false;

void FileLock::ensureInitialized()
{
   if (s_isInitialized)
      return;

   FileLock::initialize();
}

void FileLock::initialize(FilePath locksConfPath)
{
   s_isInitialized = true;

   if (locksConfPath.empty())
      locksConfPath = FilePath(kLocksConfPath);

   if (!locksConfPath.exists())
      return;

   Settings settings;
   Error error = settings.initialize(locksConfPath);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   FileLock::initialize(settings);
}

void FileLock::initialize(const Settings& settings)
{
   s_isInitialized = true;

   // default lock type
   FileLock::s_defaultType = stringToLockType(settings.get("lock-type", kLockTypeAdvisory));

   // timeout interval
   double timeoutInterval = getFieldPositive(settings, "timeout-interval", kDefaultTimeoutInterval);
   FileLock::s_timeoutInterval = boost::posix_time::seconds(timeoutInterval);

   // refresh rate
   double refreshRate = getFieldPositive(settings, "refresh-rate", kDefaultRefreshRate);
   FileLock::s_refreshRate = boost::posix_time::seconds(refreshRate);

   DEBUG_BLOCK("lock initialization")
   {
      std::cerr << "Type: "    << lockTypeToString(FileLock::s_defaultType) << std::endl;
      std::cerr << "Timeout: " << FileLock::s_timeoutInterval.total_seconds() << std::endl;
      std::cerr << "Refresh: " << FileLock::s_refreshRate.total_seconds() << std::endl;
   }
}

// default values for static members
FileLock::LockType FileLock::s_defaultType(FileLock::LOCKTYPE_ADVISORY);
boost::posix_time::seconds FileLock::s_timeoutInterval(kDefaultTimeoutInterval);
boost::posix_time::seconds FileLock::s_refreshRate(kDefaultRefreshRate);

boost::shared_ptr<FileLock> FileLock::create(LockType type)
{
   switch (type)
   {
   case LOCKTYPE_ADVISORY:  return boost::shared_ptr<FileLock>(new AdvisoryFileLock());
   case LOCKTYPE_LINKBASED: return boost::shared_ptr<FileLock>(new LinkBasedFileLock());
   }

   // shouldn't be reached
   return boost::shared_ptr<FileLock>(new AdvisoryFileLock());
}

boost::shared_ptr<FileLock> FileLock::createDefault()
{
   return FileLock::create(s_defaultType);
}

void FileLock::refresh()
{
   AdvisoryFileLock::refresh();
   LinkBasedFileLock::refresh();
}

void FileLock::cleanUp()
{
   AdvisoryFileLock::cleanUp();
   LinkBasedFileLock::cleanUp();
}

namespace {

void schedulePeriodicExecution(
      const boost::system::error_code& ec,
      boost::asio::deadline_timer& timer,
      boost::posix_time::seconds interval,
      boost::function<void()> callback)
{
   try
   {
      // bail on boost errors (these are very unexpected)
      if (ec)
      {
         LOG_ERROR(core::Error(ec, ERROR_LOCATION));
         return;
      }

      // execute callback
      callback();

      // reschedule
      boost::system::error_code errc;
      timer.expires_at(timer.expires_at() + interval, errc);
      if (errc)
      {
         LOG_ERROR(Error(errc, ERROR_LOCATION));
         return;
      }

      timer.async_wait(boost::bind(
                          schedulePeriodicExecution,
                          boost::asio::placeholders::error,
                          boost::ref(timer),
                          interval,
                          callback));
   }
   catch (...)
   {
      // swallow errors
   }
}

} // end anonymous namespace

void FileLock::refreshPeriodically(boost::asio::io_service& service,
                                   boost::posix_time::seconds interval)
{
   // protect against re-entrancy
   static bool s_isRefreshing = false;
   if (s_isRefreshing)
      return;
   s_isRefreshing = true;

   static boost::asio::deadline_timer timer(service, interval);
   timer.async_wait(boost::bind(
                       schedulePeriodicExecution,
                       boost::asio::placeholders::error,
                       boost::ref(timer),
                       interval,
                       FileLock::refresh));
}

} // end namespace core
} // end namespace rstudio
<|endoftext|>


<commit_before>// This file is part of OpenMVG, an Open Multiple View Geometry C++ library.

// Copyright (c) 2020 Romain JANVIER

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef OPENMVG_MATCHING_METRIC_HNSW_HPP
#define OPENMVG_MATCHING_METRIC_HNSW_HPP

#include "openMVG/matching/metric_hamming.hpp"

#include "third_party/hnswlib/hnswlib.h"

/*
* This file define specialized HNSW kernels for differents metrics/spaces
*/
namespace openMVG {
namespace matching {
namespace custom_hnsw{

template <typename U>
static unsigned int HammingKernel(const void *__restrict pVect1, const void *__restrict pVect2, const void *__restrict qty_ptr)
{
  constexpr openMVG::matching::Hamming<U> hamming{};
  const U *a = reinterpret_cast<const U *>(pVect1);
  const U *b = reinterpret_cast<const U *>(pVect2);
  return hamming(a, b,*(reinterpret_cast<const size_t*>(qty_ptr)));
}

template <typename U>
class HammingSpace : public hnswlib::SpaceInterface<unsigned int>
{
  hnswlib::DISTFUNC<unsigned int> fstdistfunc_;
  size_t data_size_;
  size_t dim_;

public:
  explicit HammingSpace(size_t dim)
  {
    fstdistfunc_ = HammingKernel<U>;
    dim_ = dim;
    data_size_ = dim_ * sizeof(U);
  }

  ~HammingSpace() {}

  size_t get_data_size() override
  {
    return data_size_;
  }

  hnswlib::DISTFUNC<unsigned int> get_dist_func() override
  {
    return fstdistfunc_;
  }

  void *get_dist_func_param() override
  {
    return &dim_;
  }
};

static int L1Kernel(const void *__restrict pVect1, const void *__restrict pVect2, const void *__restrict qty_ptr)
{
  size_t size = *(reinterpret_cast<const size_t*>(qty_ptr));
  size = size >> 2;
  int result = 0;
  uint8_t *a = (uint8_t *)(pVect1); // discard const
  uint8_t *b = (uint8_t *)(pVect2); // discard const

  // Process 4 items for each loop for efficiency.
  for (size_t i = 0; i < size; i++) {
    result += std::abs(*a - *b);
    a++;b++;
    result += std::abs(*a - *b);
    a++;b++;
    result += std::abs(*a - *b);
    a++;b++;
    result += std::abs(*a - *b);
    a++;b++;
  }
  return result;
}
#ifdef __SSE2__
static int L1Kernel_SSE2(const void *__restrict pVect1, const void *__restrict pVect2, const void *__restrict qty_ptr)
{
  const uint8_t *a = reinterpret_cast<const uint8_t *>(pVect1);
  const uint8_t *b = reinterpret_cast<const uint8_t *>(pVect2);
  return L1_SSE2(a, b, 128);
}
#endif

#ifdef __AVX2__
static int L1Kernel_AVX2(const void *__restrict pVect1, const void *__restrict pVect2, const void *__restrict qty_ptr)
{
  const uint8_t *a = reinterpret_cast<const uint8_t *>(pVect1);
  const uint8_t *b = reinterpret_cast<const uint8_t *>(pVect2);
  return L1_AVX2(a, b, 128);
}
#endif

class L1SpaceInteger : public hnswlib::SpaceInterface<int>
{
  hnswlib::DISTFUNC<int> fstdistfunc_;
  size_t data_size_;
  size_t dim_;

public:
  explicit L1SpaceInteger(size_t dim)
  {
    fstdistfunc_ = L1Kernel;
    #ifdef __SSE2__
    //FIXME (RJ): Kernel disabled since there are some troubles on my Linux computer
    /*if(dim == 128) {
      fstdistfunc_ = L1Kernel_SSE2;
    }*/
    #endif
    #ifdef __AVX2__
    if(dim == 128) {
      fstdistfunc_ = L1Kernel_AVX2;
    }
    #endif
    dim_ = dim;
    data_size_ = dim_ * sizeof(uint8_t);
  }

  ~L1SpaceInteger() {}

  size_t get_data_size() override
  {
    return data_size_;
  }

  hnswlib::DISTFUNC<int> get_dist_func() override
  {
    return fstdistfunc_;
  }

  void *get_dist_func_param() override
  {
    return &dim_;
  }
};

#ifdef __AVX2__
static int L2Kernel_AVX2(const void *__restrict pVect1, const void *__restrict pVect2, const void *__restrict qty_ptr)
{
  const uint8_t *a = reinterpret_cast<const uint8_t *>(pVect1);
  const uint8_t *b = reinterpret_cast<const uint8_t *>(pVect2);
  return L2_AVX2(a, b, 128);
}
#endif

class L2SpaceInteger : public hnswlib::SpaceInterface<int>
{
  hnswlib::DISTFUNC<int> fstdistfunc_;
  size_t data_size_;
  size_t dim_;

public:
  explicit L2SpaceInteger(size_t dim)
  {
    fstdistfunc_ = hnswlib::L2SqrI;
    #ifdef __AVX2__
    if(dim == 128) {
      fstdistfunc_ = L2Kernel_AVX2;
    }
    #endif
    dim_ = dim;
    data_size_ = dim_ * sizeof(uint8_t);
  }

  ~L2SpaceInteger() {}

  size_t get_data_size() override
  {
    return data_size_;
  }

  hnswlib::DISTFUNC<int> get_dist_func() override
  {
    return fstdistfunc_;
  }

  void *get_dist_func_param() override
  {
    return &dim_;
  }
};

} // namespace custom_hnsw
} // namespace matching
} // namespace openMVG
#endif // OPENMVG_MATCHING_METRIC_HNSW_HPP<commit_msg>[Matching] Fix L1 metric<commit_after>// This file is part of OpenMVG, an Open Multiple View Geometry C++ library.

// Copyright (c) 2020 Romain JANVIER

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef OPENMVG_MATCHING_METRIC_HNSW_HPP
#define OPENMVG_MATCHING_METRIC_HNSW_HPP

#include "openMVG/matching/metric_hamming.hpp"

#include "third_party/hnswlib/hnswlib.h"

/*
* This file define specialized HNSW kernels for differents metrics/spaces
*/
namespace openMVG {
namespace matching {
namespace custom_hnsw{

template <typename U>
static unsigned int HammingKernel(const void * pVect1, const void * pVect2, const void * qty_ptr)
{
  constexpr openMVG::matching::Hamming<U> hamming{};
  const U *a = reinterpret_cast<const U *>(pVect1);
  const U *b = reinterpret_cast<const U *>(pVect2);
  return hamming(a, b,*(reinterpret_cast<const size_t*>(qty_ptr)));
}

template <typename U>
class HammingSpace : public hnswlib::SpaceInterface<unsigned int>
{
  hnswlib::DISTFUNC<unsigned int> fstdistfunc_;
  size_t data_size_;
  size_t dim_;

public:
  explicit HammingSpace(size_t dim)
  {
    fstdistfunc_ = HammingKernel<U>;
    dim_ = dim;
    data_size_ = dim_ * sizeof(U);
  }

  ~HammingSpace() {}

  size_t get_data_size() override
  {
    return data_size_;
  }

  hnswlib::DISTFUNC<unsigned int> get_dist_func() override
  {
    return fstdistfunc_;
  }

  void *get_dist_func_param() override
  {
    return &dim_;
  }
};

static int L1Kernel(const void *__restrict pVect1, const void *__restrict pVect2, const void *__restrict qty_ptr)
{
  size_t size = *(reinterpret_cast<const size_t*>(qty_ptr));
  size = size >> 2;
  int result = 0;
  uint8_t *a = (uint8_t *)(pVect1); // discard const
  uint8_t *b = (uint8_t *)(pVect2); // discard const

  // Process 4 items for each loop for efficiency.
  for (size_t i = 0; i < size; i++) {
    result += std::abs(*a - *b);
    a++;b++;
    result += std::abs(*a - *b);
    a++;b++;
    result += std::abs(*a - *b);
    a++;b++;
    result += std::abs(*a - *b);
    a++;b++;
  }
  return result;
}
#ifdef __SSE2__
static int L1Kernel_SSE2(const void * pVect1, const void * pVect2, const void * qty_ptr)
{
  const uint8_t *a = reinterpret_cast<const uint8_t *>(pVect1);
  const uint8_t *b = reinterpret_cast<const uint8_t *>(pVect2);
  return L1_SSE2(a, b, 128);
}
#endif

#ifdef __AVX2__
static int L1Kernel_AVX2(const void * pVect1, const void * pVect2, const void * qty_ptr)
{
  const uint8_t *a = reinterpret_cast<const uint8_t *>(pVect1);
  const uint8_t *b = reinterpret_cast<const uint8_t *>(pVect2);
  return L1_AVX2(a, b, 128);
}
#endif

class L1SpaceInteger : public hnswlib::SpaceInterface<int>
{
  hnswlib::DISTFUNC<int> fstdistfunc_;
  size_t data_size_;
  size_t dim_;

public:
  explicit L1SpaceInteger(size_t dim)
  {
    fstdistfunc_ = L1Kernel;
    #ifdef __SSE2__
    //FIXME (RJ): Kernel disabled since there are some troubles on my Linux computer
    /*if(dim == 128) {
      fstdistfunc_ = L1Kernel_SSE2;
    }*/
    #endif
    #ifdef __AVX2__
    if(dim == 128) {
      fstdistfunc_ = L1Kernel_AVX2;
    }
    #endif
    dim_ = dim;
    data_size_ = dim_ * sizeof(uint8_t);
  }

  ~L1SpaceInteger() {}

  size_t get_data_size() override
  {
    return data_size_;
  }

  hnswlib::DISTFUNC<int> get_dist_func() override
  {
    return fstdistfunc_;
  }

  void *get_dist_func_param() override
  {
    return &dim_;
  }
};

#ifdef __AVX2__
static int L2Kernel_AVX2(const void * pVect1, const void * pVect2, const void * qty_ptr)
{
  const uint8_t *a = reinterpret_cast<const uint8_t *>(pVect1);
  const uint8_t *b = reinterpret_cast<const uint8_t *>(pVect2);
  return L2_AVX2(a, b, 128);
}
#endif

class L2SpaceInteger : public hnswlib::SpaceInterface<int>
{
  hnswlib::DISTFUNC<int> fstdistfunc_;
  size_t data_size_;
  size_t dim_;

public:
  explicit L2SpaceInteger(size_t dim)
  {
    fstdistfunc_ = hnswlib::L2SqrI;
    #ifdef __AVX2__
    if(dim == 128) {
      fstdistfunc_ = L2Kernel_AVX2;
    }
    #endif
    dim_ = dim;
    data_size_ = dim_ * sizeof(uint8_t);
  }

  ~L2SpaceInteger() {}

  size_t get_data_size() override
  {
    return data_size_;
  }

  hnswlib::DISTFUNC<int> get_dist_func() override
  {
    return fstdistfunc_;
  }

  void *get_dist_func_param() override
  {
    return &dim_;
  }
};

} // namespace custom_hnsw
} // namespace matching
} // namespace openMVG
#endif // OPENMVG_MATCHING_METRIC_HNSW_HPP<|endoftext|>


<commit_before>#ifndef PRE_VARIANT_GET_TRAIT_HPP
#define PRE_VARIANT_GET_TRAIT_HPP

#include <boost/variant.hpp>
#include <boost/type_traits.hpp>

#include <pre/json/traits/is_boost_variant.hpp>
#include <pre/variant/detail/assignable_from.hpp>

namespace pre { namespace variant {

  namespace detail {
    template<class ResultVariant, template<class T> class TraitMetafunction>
    struct get_trait_visitor : public boost::static_visitor<ResultVariant> {

      template< class U,
        typename boost::disable_if<
          assignable_from<ResultVariant, typename TraitMetafunction<U>::type>
        >::type* = nullptr
      > ResultVariant operator()(const U&) const {
        return ResultVariant{};
      }

      template< class U,
        typename boost::enable_if<
          assignable_from<ResultVariant, typename TraitMetafunction<U>::type>
        >::type* = nullptr
      > ResultVariant operator()(const U&) const {
        return typename TraitMetafunction<U>::type{};
      }
    };

    template<class Result, template<class T> class TraitMetafunction>
    struct get_value_trait_visitor : public boost::static_visitor<Result> {

      template< class U >
      Result operator()(const U&) const {
        return typename TraitMetafunction<U>::type{};
      }

    };
  }

  /**
   * \brief Runtime compile time traits access.
   *        This function gets the active type of a variant and return a runtime
   *        instantiation of the associated type found by
   *        TraitMetafunction<active type>.
   *
   * \param variant The variant whose active type will be queried for the given
   *                TraitMetafunction
   *
   * \param Result A boost::variant or any type capable to hold the runtime
   *                     instance of the TraitMetafunction result.
   *
   * \param TraitMetafunction Template metafunction which will be called on the
   *                          active type of the runtime parameter : variant.
   *
   * \param InspectedVariant A boost::variant to apply the TraitMetafunction on it's
   *                         active field.
   *
   */
  template<class Result, template<class T> class TraitMetafunction, class InspectedVariant,
    typename std::enable_if<
      pre::json::traits::is_boost_variant<Result>::value
    >::type* = nullptr
  >
  inline Result get_trait(const InspectedVariant& variant) {
    return boost::apply_visitor(detail::get_trait_visitor<Result, TraitMetafunction>{}, variant);
  }

  template<class Result, template<class T> class TraitMetafunction, class InspectedVariant,
    typename std::enable_if<
      !pre::json::traits::is_boost_variant<Result>::value
    >::type* = nullptr
  >
  inline Result get_trait(const InspectedVariant& variant) {
    return boost::apply_visitor(detail::get_value_trait_visitor<Result, TraitMetafunction>{}, variant);
  }

}}

#endif
<commit_msg>BUGFIX: Only mpl value have a default constructor, other metaprogramming library provide value via ::value, so take the one size fits-all. :D<commit_after>#ifndef PRE_VARIANT_GET_TRAIT_HPP
#define PRE_VARIANT_GET_TRAIT_HPP

#include <boost/variant.hpp>
#include <boost/type_traits.hpp>

#include <pre/json/traits/is_boost_variant.hpp>
#include <pre/variant/detail/assignable_from.hpp>

namespace pre { namespace variant {

  namespace detail {
    template<class ResultVariant, template<class T> class TraitMetafunction>
    struct get_trait_visitor : public boost::static_visitor<ResultVariant> {

      template< class U,
        typename boost::disable_if<
          assignable_from<ResultVariant, typename TraitMetafunction<U>::type>
        >::type* = nullptr
      > ResultVariant operator()(const U&) const {
        return ResultVariant{};
      }

      template< class U,
        typename boost::enable_if<
          assignable_from<ResultVariant, typename TraitMetafunction<U>::type>
        >::type* = nullptr
      > ResultVariant operator()(const U&) const {
        return typename TraitMetafunction<U>::type{};
      }
    };

    template<class Result, template<class T> class TraitMetafunction>
    struct get_value_trait_visitor : public boost::static_visitor<Result> {

      template< class U >
      Result operator()(const U&) const {
        return TraitMetafunction<U>::type::value;
      }

    };
  }

  /**
   * \brief Runtime compile time traits access.
   *        This function gets the active type of a variant and return a runtime
   *        instantiation of the associated type found by
   *        TraitMetafunction<active type>.
   *
   * \param variant The variant whose active type will be queried for the given
   *                TraitMetafunction
   *
   * \param Result A boost::variant or any type capable to hold the runtime
   *                     instance of the TraitMetafunction result.
   *
   * \param TraitMetafunction Template metafunction which will be called on the
   *                          active type of the runtime parameter : variant.
   *
   * \param InspectedVariant A boost::variant to apply the TraitMetafunction on it's
   *                         active field.
   *
   */
  template<class Result, template<class T> class TraitMetafunction, class InspectedVariant,
    typename std::enable_if<
      pre::json::traits::is_boost_variant<Result>::value
    >::type* = nullptr
  >
  inline Result get_trait(const InspectedVariant& variant) {
    return boost::apply_visitor(detail::get_trait_visitor<Result, TraitMetafunction>{}, variant);
  }

  template<class Result, template<class T> class TraitMetafunction, class InspectedVariant,
    typename std::enable_if<
      !pre::json::traits::is_boost_variant<Result>::value
    >::type* = nullptr
  >
  inline Result get_trait(const InspectedVariant& variant) {
    return boost::apply_visitor(detail::get_value_trait_visitor<Result, TraitMetafunction>{}, variant);
  }

}}

#endif
<|endoftext|>


<commit_before>/*
@title: BinaryHeap 二叉堆
@description:
    一个普通的二叉堆
@structure:
    BinaryHeap:
      T *buffer: 数组首地址 - 1
      int size: 数组长度
@note:
    需要手动指定 buffer, size
    指定 buffer 为 a[] 时 => buffer = a - 1;
*/
struct BinaryHeap {
  int *buffer;
  int size;
  // 转移函数 O(1)
  int parent(int index);
  int left(int index);
  int right(int index);
  // shiftDown
  // 对节点 n 进行下降操作
  // 将 buffer[n] 向下交换到叶子节点上。
  // 每次与孩子中较小的一个交换。 O(log(size))
  void shiftDown(int index);
  // insert
  // 插入元素 O(log(size))
  void insert(int key);
  // Find Min
  // 获取最小值 O(1)
  int findMin();
  // Remove
  // 删除 index 位置上的点 O(log(size))
  void remove(int index);
  // Delete Min
  // 删除最小值 O(log(size))
  void deleteMin();
  // Extract Min
  // 取最小值并弹出 O(log(size))
  int extractMin();
  // updateKey
  // 更新键值
  // shift down or shift up O(log(size))
  void updateKey(int index, int key);
  void IterativeMaintenance(int index);
  // 离线迭代建堆
  // Bottom-Up O(size)
  void IterativeHeapify();
};

inline int BinaryHeap::parent(int index) { return index >> 1; }
inline int BinaryHeap::left(int index) { return index << 1; }
inline int BinaryHeap::right(int index) { return (index << 1) + 1; }

void BinaryHeap::shiftDown(int index) {
  while (true) {
    if (right(index) <= size) { // left(n) < right(n) <= size
      if (compare(buffer[left(index)], buffer[right(index)])) {
        std::swap(buffer[index], buffer[left(index)]);
        index = left(index);
      } else {
        std::swap(buffer[index], buffer[right(index)]);
        index = right(index);
      }
    } else if (left(index) <= size) { // left(n) <= size < right(n)
      std::swap(buffer[index], buffer[left(index)]);
      index = left(index);
    } else { // size < left(n) < right(n)
      break;
    }
  }
}

void BinaryHeap::insert(int key) {
  int index = ++size;
  while (index > 1 && compare(key, buffer[parent(index)])) {
    buffer[index] = buffer[parent(index)];
    index = parent(index);
  }
  buffer[index] = key;
}

int BinaryHeap::findMin() { return buffer[1]; }

void BinaryHeap::remove(int index) {
  buffer[index] = buffer[size--];
  shiftDown(index);
}

void BinaryHeap::deleteMin() { remove(1); }

int BinaryHeap::extractMin() {
  int min = findMin();
  remove(1);
  return min;
}

void updateKey(int index, int key) {
  if (compare(buffer[index], key)) { // buffer[index] < key
    // increasing
    buffer[index] = key;
    IterativeMaintenance(index);
  } else if (compare(key, buffer[index])) { // key < buffer[index]
    buffer[index] = key;
    // shift up
    int p = parent(index);
    while (p >= 1) {
      if (compare(buffer[p], buffer[index])) {
        // 满足堆性质
        break;
      }
      std::swap(buffer[p], buffer[index]);
      index = p;
      p = parent(p);
    }
  } else {
    // buffer[index] == key, do nothing
  }
}

void BinaryHeap::IterativeHeapify() {
  for (int i = size; i > 0; i--) {
    IterativeMaintenance(i);
  }
}

void BinaryHeap::IterativeMaintenance(int index) {
  // heapify the heap whose root is index
  while (true) {
    if (right(index) <= size) { // left < right <= size
      if (compare(buffer[left(index)], buffer[right(index)])) {
        if (!compare(buffer[index], buffer[left(index)])) {
          std::swap(buffer[index], buffer[left(index)]);
          index = left(index);
        } else {
          break;
        }
      } else {
        if (!compare(buffer[index], buffer[right(index)])) {
          std::swap(buffer[index], buffer[right(index)]);
          index = right(index);
        } else {
          break;
        }
      }
    } else if (left(index) <= size) { // left <= size < right
      if (!compare(buffer[index], buffer[left(index)])) {
        std::swap(buffer[index], buffer[left(index)]);
        index = left(index);
        // the next one must be leaf, so we can break it
        // break;
      } else {
        break;
      }
    } else { // size < left < right: leaf
      break;
    }
  }
}<commit_msg>FIX: BinaryHeap dependence<commit_after>/*
@title: BinaryHeap 二叉堆
@description:
    一个普通的二叉堆
@structure:
    BinaryHeap:
      T *buffer: 数组首地址 - 1
      int size: 数组长度
@dependence:
    bool compare(int a, int b); // 给出比较关系
@note:
    需要手动指定 buffer, size
    指定 buffer 为 a[] 时 => buffer = a - 1;
*/
struct BinaryHeap {
  int *buffer;
  int size;
  // 转移函数 O(1)
  int parent(int index);
  int left(int index);
  int right(int index);
  // shiftDown
  // 对节点 n 进行下降操作
  // 将 buffer[n] 向下交换到叶子节点上。
  // 每次与孩子中较小的一个交换。 O(log(size))
  void shiftDown(int index);
  // insert
  // 插入元素 O(log(size))
  void insert(int key);
  // Find Min
  // 获取最小值 O(1)
  int findMin();
  // Remove
  // 删除 index 位置上的点 O(log(size))
  void remove(int index);
  // Delete Min
  // 删除最小值 O(log(size))
  void deleteMin();
  // Extract Min
  // 取最小值并弹出 O(log(size))
  int extractMin();
  // updateKey
  // 更新键值
  // shift down or shift up O(log(size))
  void updateKey(int index, int key);
  void IterativeMaintenance(int index);
  // 离线迭代建堆
  // Bottom-Up O(size)
  void IterativeHeapify();
};

inline int BinaryHeap::parent(int index) { return index >> 1; }
inline int BinaryHeap::left(int index) { return index << 1; }
inline int BinaryHeap::right(int index) { return (index << 1) + 1; }

void BinaryHeap::shiftDown(int index) {
  while (true) {
    if (right(index) <= size) { // left(n) < right(n) <= size
      if (compare(buffer[left(index)], buffer[right(index)])) {
        std::swap(buffer[index], buffer[left(index)]);
        index = left(index);
      } else {
        std::swap(buffer[index], buffer[right(index)]);
        index = right(index);
      }
    } else if (left(index) <= size) { // left(n) <= size < right(n)
      std::swap(buffer[index], buffer[left(index)]);
      index = left(index);
    } else { // size < left(n) < right(n)
      break;
    }
  }
}

void BinaryHeap::insert(int key) {
  int index = ++size;
  while (index > 1 && compare(key, buffer[parent(index)])) {
    buffer[index] = buffer[parent(index)];
    index = parent(index);
  }
  buffer[index] = key;
}

int BinaryHeap::findMin() { return buffer[1]; }

void BinaryHeap::remove(int index) {
  buffer[index] = buffer[size--];
  shiftDown(index);
}

void BinaryHeap::deleteMin() { remove(1); }

int BinaryHeap::extractMin() {
  int min = findMin();
  remove(1);
  return min;
}

void updateKey(int index, int key) {
  if (compare(buffer[index], key)) { // buffer[index] < key
    // increasing
    buffer[index] = key;
    IterativeMaintenance(index);
  } else if (compare(key, buffer[index])) { // key < buffer[index]
    buffer[index] = key;
    // shift up
    int p = parent(index);
    while (p >= 1) {
      if (compare(buffer[p], buffer[index])) {
        // 满足堆性质
        break;
      }
      std::swap(buffer[p], buffer[index]);
      index = p;
      p = parent(p);
    }
  } else {
    // buffer[index] == key, do nothing
  }
}

void BinaryHeap::IterativeHeapify() {
  for (int i = size; i > 0; i--) {
    IterativeMaintenance(i);
  }
}

void BinaryHeap::IterativeMaintenance(int index) {
  // heapify the heap whose root is index
  while (true) {
    if (right(index) <= size) { // left < right <= size
      if (compare(buffer[left(index)], buffer[right(index)])) {
        if (!compare(buffer[index], buffer[left(index)])) {
          std::swap(buffer[index], buffer[left(index)]);
          index = left(index);
        } else {
          break;
        }
      } else {
        if (!compare(buffer[index], buffer[right(index)])) {
          std::swap(buffer[index], buffer[right(index)]);
          index = right(index);
        } else {
          break;
        }
      }
    } else if (left(index) <= size) { // left <= size < right
      if (!compare(buffer[index], buffer[left(index)])) {
        std::swap(buffer[index], buffer[left(index)]);
        index = left(index);
        // the next one must be leaf, so we can break it
        // break;
      } else {
        break;
      }
    } else { // size < left < right: leaf
      break;
    }
  }
}<|endoftext|>


<commit_before>#define UNICODE
#include <windows.h>
#include <ole2.h>
#include <AtlBase.h>
#include <algorithm>
#include <sstream>
#include <string>
#include "FSAPI.h"
#include "dictationbridge-core/master/master.h"
#include "combool.h"

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleacc.lib")

#define ERR(x, msg) do { \
if(x != S_OK) {\
MessageBox(NULL, msg L"\n", NULL, NULL);\
exit(1);\
}\
} while(0)

CComPtr<IJawsApi> pJfw =nullptr;

void initSpeak() {
	CLSID JFWClass;
	auto res = CLSIDFromProgID(L"FreedomSci.JawsApi", &JFWClass);
	ERR(res, L"Couldn't get Jaws interface ID");
res =pJfw.CoCreateInstance(JFWClass);
	ERR(res, L"Couldn't create Jaws interface");
}

void speak(std::wstring text) {
CComBSTR bS =CComBSTR(text.size(), text.data());
CComBool silence =false;
CComBool bResult;
	pJfw->SayString(bS, silence, &bResult);
}

void WINAPI textCallback(HWND hwnd, DWORD startPosition, LPCWSTR textUnprocessed) {
	//We need to replace \r with nothing.
std::wstring text =textUnprocessed;
text.erase(std::remove_if(begin(text), end(text), [] (wchar_t checkingCharacter) {
		return checkingCharacter == '\r';
	}), end(text));

	if(text.compare(L"\n\n") ==0
|| text.compare(L"") ==0 //new paragraph in word.
	) {
		speak(L"New paragraph.");
	}
	else if(text.compare(L"\n") ==0) {
		speak(L"New line.");
	}
	else {
speak(text.c_str());
}
}

void WINAPI textDeletedCallback(HWND hwnd, DWORD startPosition, LPCWSTR text) {
std::wstringstream deletedText;
deletedText << "Deleted ";
deletedText << text;
	speak(deletedText.str().c_str());
}

//These are string constants for the microphone status, as well as the status itself:
//The pointer below is set to the last one we saw.
std::wstring MICROPHONE_OFF = L"Dragon's microphone is off;";
std::wstring MICROPHONE_ON = L"Normal mode: You can dictate and use voice";
std::wstring MICROPHONE_SLEEPING = L"The microphone is asleep;";

std::wstring microphoneState;

void announceMicrophoneState(const std::wstring state) {
	if(state == MICROPHONE_ON) speak(L"Microphone on.");
	else if(state == MICROPHONE_OFF) speak(L"Microphone off.");
	else if(state == MICROPHONE_SLEEPING) speak(L"Microphone sleeping.");
	else speak(L"Microphone in unknown state.");
}

wchar_t processNameBuffer[1024] = {0};

void CALLBACK nameChanged(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime) {
	//First, is it coming from natspeak.exe?
	DWORD procId;
	GetWindowThreadProcessId(hwnd, &procId);
	auto procHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, procId);
	//We can't recover from this failing, so abort.
	if(procHandle == NULL) return;
	DWORD len = 1024;
	auto res = QueryFullProcessImageName(procHandle, 0, processNameBuffer, &len);
	CloseHandle(procHandle);
	if(res == 0) return;
std::wstring processName =processNameBuffer;
	if(processName.find(L"dragonbar.exe") == std::string::npos
		&& processName.find(L"natspeak.exe") == std::string::npos) return;
	//Attempt to get the new text.
CComPtr<IAccessible> pAcc;
CComVariant vChild;
	HRESULT hres = AccessibleObjectFromEvent(hwnd, idObject, idChild, &pAcc, &vChild);
	if(hres != S_OK) return;
CComBSTR bName;
	hres = pAcc->get_accName(vChild, &bName);
	if(hres != S_OK) return;
std::wstring name =bName;
	const std::wstring possibles[] = {MICROPHONE_ON, MICROPHONE_OFF, MICROPHONE_SLEEPING};
std::wstring newState = microphoneState;
	for(int i = 0; i < 3; i++) {
		if(name.find(possibles[i]) != std::string::npos) {
			newState = possibles[i];
			break;
		}
	}
	if(newState != microphoneState) {
		announceMicrophoneState(newState);
		microphoneState = newState;
	}
}

int keepRunning = 1; // Goes to 0 on WM_CLOSE.
LPCTSTR msgWindowClassName = L"DictationBridgeJFWHelper";

LRESULT CALLBACK exitProc(_In_ HWND hwnd, _In_ UINT msg, _In_ WPARAM wparam, _In_ LPARAM lparam) {
	if(msg == WM_CLOSE) keepRunning = 0;
	return DefWindowProc(hwnd, msg, wparam, lparam);
}

int CALLBACK WinMain(_In_ HINSTANCE hInstance,
	_In_ HINSTANCE hPrevInstance,
	_In_ LPSTR lpCmdLine,
	_In_ int nCmdShow) {
	// First, is a core running?
	if(FindWindow(msgWindowClassName, NULL)) {
		MessageBox(NULL, L"Core already running.", NULL, NULL);
		return 0;
	}
	WNDCLASS windowClass = {0};
	windowClass.lpfnWndProc = exitProc;
	windowClass.hInstance = hInstance;
	windowClass.lpszClassName = msgWindowClassName;
	auto msgWindowClass = RegisterClass(&windowClass);
	if(msgWindowClass == 0) {
		MessageBox(NULL, L"Failed to register window class.", NULL, NULL);
		return 0;
	}
	auto msgWindowHandle = CreateWindow(msgWindowClassName, NULL, NULL, NULL, NULL, NULL, NULL, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
	if(msgWindowHandle == 0) {
		MessageBox(NULL, L"Failed to create message-only window.", NULL, NULL);
		return 0;
	}
	HRESULT res;
	res = OleInitialize(NULL);
	ERR(res, L"Couldn't initialize OLE");
	initSpeak();
	auto started = DBMaster_Start();
	if(!started) {
		printf("Couldn't start DictationBridge-core\n");
		return 1;
	}
	DBMaster_SetTextInsertedCallback(textCallback);
	DBMaster_SetTextDeletedCallback(textDeletedCallback);
	if(SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, NULL, nameChanged, 0, 0, WINEVENT_OUTOFCONTEXT) == 0) {
		printf("Couldn't register to receive events\n");
		return 1;
	}
	MSG msg;
	while(GetMessage(&msg, NULL, NULL, NULL) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
		if(keepRunning == 0) break;
	}
	DBMaster_Stop();
	OleUninitialize();
	DestroyWindow(msgWindowHandle);
	return 0;
}
<commit_msg>Add notification when dragon hasn't understood the dictation.<commit_after>#define UNICODE
#include <windows.h>
#include <ole2.h>
#include <AtlBase.h>
#include <algorithm>
#include <sstream>
#include <string>
#include "FSAPI.h"
#include "dictationbridge-core/master/master.h"
#include "combool.h"

#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleacc.lib")

#define ERR(x, msg) do { \
if(x != S_OK) {\
MessageBox(NULL, msg L"\n", NULL, NULL);\
exit(1);\
}\
} while(0)

CComPtr<IJawsApi> pJfw =nullptr;

void initSpeak() {
	CLSID JFWClass;
	auto res = CLSIDFromProgID(L"FreedomSci.JawsApi", &JFWClass);
	ERR(res, L"Couldn't get Jaws interface ID");
res =pJfw.CoCreateInstance(JFWClass);
	ERR(res, L"Couldn't create Jaws interface");
}

void speak(std::wstring text) {
CComBSTR bS =CComBSTR(text.size(), text.data());
CComBool silence =false;
CComBool bResult;
	pJfw->SayString(bS, silence, &bResult);
}

void WINAPI textCallback(HWND hwnd, DWORD startPosition, LPCWSTR textUnprocessed) {
	//We need to replace \r with nothing.
std::wstring text =textUnprocessed;
text.erase(std::remove_if(begin(text), end(text), [] (wchar_t checkingCharacter) {
		return checkingCharacter == '\r';
	}), end(text));

	if(text.compare(L"\n\n") ==0
|| text.compare(L"") ==0 //new paragraph in word.
	) {
		speak(L"New paragraph.");
	}
	else if(text.compare(L"\n") ==0) {
		speak(L"New line.");
	}
	else {
speak(text.c_str());
}
}

void WINAPI textDeletedCallback(HWND hwnd, DWORD startPosition, LPCWSTR text) {
std::wstringstream deletedText;
deletedText << "Deleted ";
deletedText << text;
	speak(deletedText.str().c_str());
}

//These are string constants for the microphone status, as well as the status itself:
//The pointer below is set to the last one we saw.
std::wstring MICROPHONE_OFF = L"Dragon's microphone is off;";
std::wstring MICROPHONE_ON = L"Normal mode: You can dictate and use voice";
std::wstring MICROPHONE_SLEEPING = L"The microphone is asleep;";

std::wstring microphoneState;
//This is a constant for the text indicating dragon hasn't understood what a user has dictated.
const std::wstring DictationWasNotUnderstood =L"<???>";

void announceMicrophoneState(const std::wstring state) {
	if(state == MICROPHONE_ON) speak(L"Microphone on.");
	else if(state == MICROPHONE_OFF) speak(L"Microphone off.");
	else if(state == MICROPHONE_SLEEPING) speak(L"Microphone sleeping.");
	else speak(L"Microphone in unknown state.");
}

wchar_t processNameBuffer[1024] = {0};

void CALLBACK nameChanged(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime) {
	//First, is it coming from natspeak.exe?
	DWORD procId;
	GetWindowThreadProcessId(hwnd, &procId);
	auto procHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, procId);
	//We can't recover from this failing, so abort.
	if(procHandle == NULL) return;
	DWORD len = 1024;
	auto res = QueryFullProcessImageName(procHandle, 0, processNameBuffer, &len);
	CloseHandle(procHandle);
	if(res == 0) return;
std::wstring processName =processNameBuffer;
	if(processName.find(L"dragonbar.exe") == std::string::npos
		&& processName.find(L"natspeak.exe") == std::string::npos) return;
	//Attempt to get the new text.
CComPtr<IAccessible> pAcc;
CComVariant vChild;
	HRESULT hres = AccessibleObjectFromEvent(hwnd, idObject, idChild, &pAcc, &vChild);
	if(hres != S_OK) return;
CComBSTR bName;
	hres = pAcc->get_accName(vChild, &bName);
	if(hres != S_OK) return;
std::wstring name =bName;
//check to see whether Dragon understood the user.
if (name .compare(DictationWasNotUnderstood) ==0)
{
speak(L"I do not understand.");
return;
}
	const std::wstring possibles[] = {MICROPHONE_ON, MICROPHONE_OFF, MICROPHONE_SLEEPING};
std::wstring newState = microphoneState;
	for(int i = 0; i < 3; i++) {
		if(name.find(possibles[i]) != std::string::npos) {
			newState = possibles[i];
			break;
		}
	}
	if(newState != microphoneState) {
		announceMicrophoneState(newState);
		microphoneState = newState;
	}
}

int keepRunning = 1; // Goes to 0 on WM_CLOSE.
LPCTSTR msgWindowClassName = L"DictationBridgeJFWHelper";

LRESULT CALLBACK exitProc(_In_ HWND hwnd, _In_ UINT msg, _In_ WPARAM wparam, _In_ LPARAM lparam) {
	if(msg == WM_CLOSE) keepRunning = 0;
	return DefWindowProc(hwnd, msg, wparam, lparam);
}

int CALLBACK WinMain(_In_ HINSTANCE hInstance,
	_In_ HINSTANCE hPrevInstance,
	_In_ LPSTR lpCmdLine,
	_In_ int nCmdShow) {
	// First, is a core running?
	if(FindWindow(msgWindowClassName, NULL)) {
		MessageBox(NULL, L"Core already running.", NULL, NULL);
		return 0;
	}
	WNDCLASS windowClass = {0};
	windowClass.lpfnWndProc = exitProc;
	windowClass.hInstance = hInstance;
	windowClass.lpszClassName = msgWindowClassName;
	auto msgWindowClass = RegisterClass(&windowClass);
	if(msgWindowClass == 0) {
		MessageBox(NULL, L"Failed to register window class.", NULL, NULL);
		return 0;
	}
	auto msgWindowHandle = CreateWindow(msgWindowClassName, NULL, NULL, NULL, NULL, NULL, NULL, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
	if(msgWindowHandle == 0) {
		MessageBox(NULL, L"Failed to create message-only window.", NULL, NULL);
		return 0;
	}
	HRESULT res;
	res = OleInitialize(NULL);
	ERR(res, L"Couldn't initialize OLE");
	initSpeak();
	auto started = DBMaster_Start();
	if(!started) {
		printf("Couldn't start DictationBridge-core\n");
		return 1;
	}
	DBMaster_SetTextInsertedCallback(textCallback);
	DBMaster_SetTextDeletedCallback(textDeletedCallback);
	if(SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, NULL, nameChanged, 0, 0, WINEVENT_OUTOFCONTEXT) == 0) {
		printf("Couldn't register to receive events\n");
		return 1;
	}
	MSG msg;
	while(GetMessage(&msg, NULL, NULL, NULL) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
		if(keepRunning == 0) break;
	}
	DBMaster_Stop();
	OleUninitialize();
	DestroyWindow(msgWindowHandle);
	return 0;
}
<|endoftext|>


<commit_before>#include <functional>
#include <future>
#include "kernel.h"
#include "raster.h"
#include "symboltable.h"
#include "ilwisoperation.h"
#include "rasterinterpolator.h"
#include "resampleraster.h"

using namespace Ilwis;
using namespace BaseOperations;

REGISTER_OPERATION(ResampleRaster)

Ilwis::OperationImplementation *ResampleRaster::create(quint64 metaid, const Ilwis::OperationExpression &expr)
{
    return new ResampleRaster(metaid, expr);
}

ResampleRaster::ResampleRaster()
{
}

ResampleRaster::ResampleRaster(quint64 metaid, const Ilwis::OperationExpression &expr) :
    OperationImplementation(metaid, expr),
    _method(RasterInterpolator::ipBICUBIC)
{
}

bool ResampleRaster::execute(ExecutionContext *ctx, SymbolTable& symTable)
{
    if (_prepState == sNOTPREPARED)
        if((_prepState = prepare(ctx,symTable)) != sPREPARED)
            return false;
    IRasterCoverage outputRaster = _outputObj.as<RasterCoverage>();
    IRasterCoverage inputRaster = _inputObj.as<RasterCoverage>();
    SPTranquilizer trq = kernel()->createTrq("resample", "", outputRaster->size().ysize(),1);

    BoxedAsyncFunc resampleFun = [&](const BoundingBox& box) -> bool {
        PixelIterator iterOut(outputRaster,box);
        iterOut.setTranquilizer(trq);
        RasterInterpolator interpolator(inputRaster, _method);
        PixelIterator iterEnd = iterOut.end();
        bool equalCsy = inputRaster->coordinateSystem()->isEqual(outputRaster->coordinateSystem().ptr());
        while(iterOut != iterEnd) {
            Pixel position = iterOut.position();
            Coordinate coord = outputRaster->georeference()->pixel2Coord(Pixeld(position.x,(position.y)));
            if ( !equalCsy)
                coord = inputRaster->coordinateSystem()->coord2coord(outputRaster->coordinateSystem(),coord);
            *iterOut = interpolator.coord2value(coord, iterOut.position().z);
            ++iterOut;
        }
        return true;
    };

    bool resource = OperationHelperRaster::execute(ctx, resampleFun, outputRaster);

    if ( resource && ctx != 0) {
        QVariant value;
        value.setValue<IRasterCoverage>(outputRaster);
        ctx->setOutput(symTable,value,outputRaster->name(), itRASTER, outputRaster->source() );
    }
    return resource;
}

Ilwis::OperationImplementation::State ResampleRaster::prepare(ExecutionContext *, const SymbolTable & )
{
    QString raster = _expression.parm(0).value();
    QString outputName = _expression.parm(0,false).value();

    if (!_inputObj.prepare(raster, itRASTER)) {
        ERROR2(ERR_COULD_NOT_LOAD_2,raster,"");
        return sPREPAREFAILED;
    }
    _outputObj = OperationHelperRaster::initialize(_inputObj,itRASTER, itDOMAIN);
    if ( !_outputObj.isValid()) {
        ERROR1(ERR_NO_INITIALIZED_1, "output rastercoverage");
        return sPREPAREFAILED;
    }
    IGeoReference grf;
    grf.prepare(_expression.parm(1).value());
    if ( !grf.isValid()) {
        return sPREPAREFAILED;
    }
    IRasterCoverage outputRaster = _outputObj.as<RasterCoverage>();
    outputRaster->georeference(grf);
    Size<> sz = grf->size();
    if ( sz.isNull()){
        ERROR1(ERR_NO_INITIALIZED_1, "output georeference");
        return sPREPAREFAILED;
    }
    sz.zsize(_inputObj.as<RasterCoverage>()->size().zsize());
    outputRaster->size(sz);
    Envelope env = grf->pixel2Coord(grf->size());
    outputRaster->envelope(env);
    if ( outputName != sUNDEF)
        outputRaster->name(outputName);

    QString method = _expression.parm(2).value();
    if ( method.toLower() == "nearestneighbour")
        _method = RasterInterpolator::ipNEARESTNEIGHBOUR;
    else if ( method.toLower() == "bilinear")
        _method = RasterInterpolator::ipBILINEAR;
    else if (  method.toLower() == "bicubic")
        _method =RasterInterpolator::ipBICUBIC;
    else {
        ERROR3(ERR_ILLEGAL_PARM_3,"method",method,"resample");
        return sPREPAREFAILED;
    }

    return sPREPARED;
}

quint64 ResampleRaster::createMetadata()
{

    OperationResource operation({"ilwis://operations/resample"});
    operation.setSyntax("resample(inputgridcoverage,targetgeoref,nearestneighbour|bilinear|bicubic)");
    operation.setDescription(TR("translates a rastercoverage from one geometry (coordinatesystem+georeference) to another"));
    operation.setInParameterCount({3});
    operation.addInParameter(0,itRASTER, TR("input rastercoverage"),TR("input rastercoverage with domain any domain"));
    operation.addInParameter(1,itGEOREF,  TR("target georeference"),TR("the georeference to which the input coverage will be morphed"));
    operation.addInParameter(2,itSTRING, TR("Resampling method"),TR("The method used to aggregate pixels from the input map in the geometry of the output map") );
    operation.setOutParameterCount({1});
    operation.addOutParameter(0,itRASTER, TR("output rastercoverage"), TR("output rastercoverage with the domain of the input map"));
    operation.setKeywords("raster, geometry, transformation");

    mastercatalog()->addItems({operation});
    return operation.id();
}

<commit_msg>generates an error message when trying to use csy unknown for a resample<commit_after>#include <functional>
#include <future>
#include "kernel.h"
#include "raster.h"
#include "symboltable.h"
#include "ilwisoperation.h"
#include "rasterinterpolator.h"
#include "resampleraster.h"

using namespace Ilwis;
using namespace BaseOperations;

REGISTER_OPERATION(ResampleRaster)

Ilwis::OperationImplementation *ResampleRaster::create(quint64 metaid, const Ilwis::OperationExpression &expr)
{
    return new ResampleRaster(metaid, expr);
}

ResampleRaster::ResampleRaster()
{
}

ResampleRaster::ResampleRaster(quint64 metaid, const Ilwis::OperationExpression &expr) :
    OperationImplementation(metaid, expr),
    _method(RasterInterpolator::ipBICUBIC)
{
}

bool ResampleRaster::execute(ExecutionContext *ctx, SymbolTable& symTable)
{
    if (_prepState == sNOTPREPARED)
        if((_prepState = prepare(ctx,symTable)) != sPREPARED)
            return false;
    IRasterCoverage outputRaster = _outputObj.as<RasterCoverage>();
    IRasterCoverage inputRaster = _inputObj.as<RasterCoverage>();
    SPTranquilizer trq = kernel()->createTrq("resample", "", outputRaster->size().ysize(),1);

    BoxedAsyncFunc resampleFun = [&](const BoundingBox& box) -> bool {
        PixelIterator iterOut(outputRaster,box);
        iterOut.setTranquilizer(trq);
        RasterInterpolator interpolator(inputRaster, _method);
        PixelIterator iterEnd = iterOut.end();
        bool equalCsy = inputRaster->coordinateSystem()->isEqual(outputRaster->coordinateSystem().ptr());
        while(iterOut != iterEnd) {
            Pixel position = iterOut.position();
            Coordinate coord = outputRaster->georeference()->pixel2Coord(Pixeld(position.x,(position.y)));
            if ( !equalCsy)
                coord = inputRaster->coordinateSystem()->coord2coord(outputRaster->coordinateSystem(),coord);
            *iterOut = interpolator.coord2value(coord, iterOut.position().z);
            ++iterOut;
        }
        return true;
    };

    bool resource = OperationHelperRaster::execute(ctx, resampleFun, outputRaster);

    if ( resource && ctx != 0) {
        QVariant value;
        value.setValue<IRasterCoverage>(outputRaster);
        ctx->setOutput(symTable,value,outputRaster->name(), itRASTER, outputRaster->source() );
    }
    return resource;
}

Ilwis::OperationImplementation::State ResampleRaster::prepare(ExecutionContext *, const SymbolTable & )
{
    QString raster = _expression.parm(0).value();
    QString outputName = _expression.parm(0,false).value();

    if (!_inputObj.prepare(raster, itRASTER)) {
        ERROR2(ERR_COULD_NOT_LOAD_2,raster,"");
        return sPREPAREFAILED;
    }
    _outputObj = OperationHelperRaster::initialize(_inputObj,itRASTER, itDOMAIN);
    if ( !_outputObj.isValid()) {
        ERROR1(ERR_NO_INITIALIZED_1, "output rastercoverage");
        return sPREPAREFAILED;
    }
    IGeoReference grf;
    grf.prepare(_expression.parm(1).value());
    if ( !grf.isValid()) {
        return sPREPAREFAILED;
    }
    IRasterCoverage outputRaster = _outputObj.as<RasterCoverage>();
    outputRaster->georeference(grf);
    Size<> sz = grf->size();
    if ( sz.isNull()){
        ERROR1(ERR_NO_INITIALIZED_1, "output georeference");
        return sPREPAREFAILED;
    }
    sz.zsize(_inputObj.as<RasterCoverage>()->size().zsize());
    outputRaster->size(sz);
    Envelope env = grf->pixel2Coord(grf->size());
    outputRaster->envelope(env);
    if ( outputName != sUNDEF)
        outputRaster->name(outputName);

    if ( outputRaster->coordinateSystem()->code() == "unknown" || _inputObj.as<RasterCoverage>()->coordinateSystem()->code() == "unknown"){
        ERROR2(ERR_OPERATION_NOTSUPPORTED2,"resample","coordinatesystem unknown");
        return sPREPAREFAILED;
    }

    QString method = _expression.parm(2).value();
    if ( method.toLower() == "nearestneighbour")
        _method = RasterInterpolator::ipNEARESTNEIGHBOUR;
    else if ( method.toLower() == "bilinear")
        _method = RasterInterpolator::ipBILINEAR;
    else if (  method.toLower() == "bicubic")
        _method =RasterInterpolator::ipBICUBIC;
    else {
        ERROR3(ERR_ILLEGAL_PARM_3,"method",method,"resample");
        return sPREPAREFAILED;
    }

    return sPREPARED;
}

quint64 ResampleRaster::createMetadata()
{

    OperationResource operation({"ilwis://operations/resample"});
    operation.setSyntax("resample(inputgridcoverage,targetgeoref,nearestneighbour|bilinear|bicubic)");
    operation.setDescription(TR("translates a rastercoverage from one geometry (coordinatesystem+georeference) to another"));
    operation.setInParameterCount({3});
    operation.addInParameter(0,itRASTER, TR("input rastercoverage"),TR("input rastercoverage with domain any domain"));
    operation.addInParameter(1,itGEOREF,  TR("target georeference"),TR("the georeference to which the input coverage will be morphed"));
    operation.addInParameter(2,itSTRING, TR("Resampling method"),TR("The method used to aggregate pixels from the input map in the geometry of the output map") );
    operation.setOutParameterCount({1});
    operation.addOutParameter(0,itRASTER, TR("output rastercoverage"), TR("output rastercoverage with the domain of the input map"));
    operation.setKeywords("raster, geometry, transformation");

    mastercatalog()->addItems({operation});
    return operation.id();
}

<|endoftext|>