<commit_before>#include "Halide.h"

using namespace Halide;
using namespace Halide::Internal;

class ValidateInterleavedPipeline: public IRMutator {
protected:
//
// This is roughly the structure that we are trying to validate in this custom pass:
//
// parallel<Renderscript> (result$2.s0.y$2.__block_id_y, 0, result$2.extent.1) {
//   parallel<Renderscript> (result$2.s0.x$2.__block_id_x, 0, result$2.extent.0) {
//     ...
//     parallel<Renderscript> (.__thread_id_x, 0, 1) {
//       for<Renderscript> (result$2.s0.c$2, 0, 4) {
//         image_store("result$2",
//                     result$2.buffer,
//                     (result$2.s0.x$2.__block_id_x + result$2.min.0),
//                     (result$2.s0.y$2.__block_id_y + result$2.min.1),
//                     result$2.s0.c$2,
//                     image_load("input",
//                                input.buffer,
//                                ((result$2.s0.x$2.__block_id_x + result$2.min.0) - input.min.0),
//                                input.extent.0,
//                                ((result$2.s0.y$2.__block_id_y + result$2.min.1) - input.min.1),
//                                input.extent.1,
//                                result$2.s0.c$2,
//                                4))
//       }
//     }
//     ...
//   }
// }
//
    using IRMutator::visit;

    virtual void visit(const Call *call) {
        if (in_pipeline && call->call_type == Call::CallType::Intrinsic && call->name == Call::image_store) {
            assert(for_nest_level == 4);

            std::map<std::string, Expr> matches;

            assert(expr_match(
                StringImm::make("result"),
                call->args[0],
                matches));
            assert(expr_match(
                Variable::make(Handle(1), "result.buffer"),
                call->args[1],
                matches));
            assert(expr_match(
                Variable::make(Int(32), "result.s0.x.__block_id_x") + Variable::make(Int(32), "result.min.0"),
                call->args[2],
                matches));
            assert(expr_match(
                Variable::make(Int(32), "result.s0.y.__block_id_y") + Variable::make(Int(32), "result.min.1"),
                call->args[3],
                matches));
            assert(expr_match(
                Variable::make(Int(32), "result.s0.c"),
                call->args[4],
                matches));
            assert(expr_match(
                Call::make(
                    UInt(8),
                    Call::image_load,
                    {
                        StringImm::make("input"),
                        Variable::make(Handle(1), "input.buffer"),
                        (Variable::make(Int(32), "result.s0.x.__block_id_x") +
                            Variable::make(Int(32), "result.min.0")) -
                            Variable::make(Int(32), "input.min.0"),
                        Variable::make(Int(32), "input.extent.0"),
                        (Variable::make(Int(32), "result.s0.y.__block_id_y") +
                            Variable::make(Int(32), "result.min.1")) -
                            Variable::make(Int(32), "input.min.1"),
                        Variable::make(Int(32), "input.extent.1"),
                        Variable::make(Int(32), "result.s0.c"),
                        IntImm::make(channels)
                    },
                    Call::CallType::Intrinsic),
                call->args[5],
                matches));
        }
        IRMutator::visit(call);
    }

    void visit(const For *op) {
        if (in_pipeline) {
            assert(for_nest_level >= 0); // For-loop should show up in Pipeline.
            for_nest_level++;
            if (for_nest_level <= 3) {
                assert(op->for_type == ForType::Parallel);
            }
            assert(op->device_api == DeviceAPI::Renderscript);
        }
        IRMutator::visit(op);
    }

    void visit(const ProducerConsumer *op) {
        assert(!in_pipeline); // There should be only one pipeline in the test.
        for_nest_level = 0;
        in_pipeline = true;

        assert(op->produce.defined());
        assert(!op->update.defined());
        assert(op->consume.defined());

        IRMutator::visit(op);
        stmt = Stmt();
    }

    int for_nest_level = -1;
    bool in_pipeline = false;
    int channels;

public:
    ValidateInterleavedPipeline(int _channels) : channels(_channels) {}
};

class ValidateInterleavedVectorizedPipeline: public ValidateInterleavedPipeline {
    using ValidateInterleavedPipeline::visit;

    virtual void visit(const Call *call) {
        if (in_pipeline && call->call_type == Call::CallType::Intrinsic && call->name == Call::image_store) {
            assert(for_nest_level == 3); // Should be three nested for-loops before we get to the first call.

            std::map<std::string, Expr> matches;

            assert(expr_match(
                Broadcast::make(StringImm::make("result"), channels),
                call->args[0],
                matches));
            assert(expr_match(
                Broadcast::make(Variable::make(Handle(1), "result.buffer"), channels),
                call->args[1],
                matches));
            assert(expr_match(
                Broadcast::make(Variable::make(Int(32), "result.s0.x.__block_id_x") + Variable::make(Int(32), "result.min.0"), channels),
                call->args[2],
                matches));
            assert(expr_match(
                Broadcast::make(Variable::make(Int(32), "result.s0.y.__block_id_y") + Variable::make(Int(32), "result.min.1"), channels),
                call->args[3],
                matches));
            assert(expr_match(
                Ramp::make(0, 1, channels), call->args[4], matches));
            assert(expr_match(
                Call::make(
                    UInt(8, channels),
                    Call::image_load,
                    {
                        Broadcast::make(StringImm::make("input"), channels),
                        Broadcast::make(Variable::make(Handle(1), "input.buffer"), channels),
                        Broadcast::make(
                            Add::make(
                                Variable::make(Int(32), "result.s0.x.__block_id_x"),
                                Variable::make(Int(32), "result.min.0")) -
                            Variable::make(Int(32), "input.min.0"),
                            channels),
                        Broadcast::make(Variable::make(Int(32), "input.extent.0"), channels),
                        Broadcast::make(
                            Add::make(
                                Variable::make(Int(32), "result.s0.y.__block_id_y"),
                                Variable::make(Int(32), "result.min.1")) -
                            Variable::make(Int(32), "input.min.1"),
                            channels),
                        Broadcast::make(Variable::make(Int(32), "input.extent.1"), channels),
                        Ramp::make(0, 1, channels),
                        Broadcast::make(IntImm::make(channels), channels)
                    },
                    Call::CallType::Intrinsic),
                call->args[5],
                matches));
        }
        IRMutator::visit(call);
    }
public:
    ValidateInterleavedVectorizedPipeline(int _channels) : ValidateInterleavedPipeline(_channels) {}
};

Image<uint8_t> make_interleaved_image(uint8_t *host, int W, int H, int channels) {
    buffer_t buf = { 0 };
    buf.host = host;
    buf.extent[0] = W;
    buf.stride[0] = channels;
    buf.extent[1] = H;
    buf.stride[1] = buf.stride[0] * buf.extent[0];
    buf.extent[2] = channels;
    buf.stride[2] = 1;
    buf.elem_size = 1;
    return Image<uint8_t>(&buf);
}

void copy_interleaved(bool vectorized = false, int channels = 4) {
    ImageParam input8(UInt(8), 3, "input");
    input8.set_stride(0, channels)
        .set_stride(1, Halide::Expr())
        .set_stride(2, 1)
        .set_bounds(2, 0, channels);  // expecting interleaved image
    uint8_t *in_buf = new uint8_t[128 * 128 * channels];
    uint8_t *out_buf = new uint8_t[128 * 128 * channels];
    Image<uint8_t> in = make_interleaved_image(in_buf, 128, 128, channels);
    Image<uint8_t> out = make_interleaved_image(out_buf, 128, 128, channels);
    input8.set(in);

    Var x, y, c;
    Func result("result");
    result(x, y, c) = input8(x, y, c);
    result.output_buffer()
        .set_stride(0, channels)
        .set_stride(1, Halide::Expr())
        .set_stride(2, 1)
        .set_bounds(2, 0, channels);  // expecting interleaved image

    result.bound(c, 0, channels);
    result.shader(x, y, c, DeviceAPI::Renderscript);
    if (vectorized) result.vectorize(c);

    result.add_custom_lowering_pass(
        vectorized?
            new ValidateInterleavedVectorizedPipeline(channels):
            new ValidateInterleavedPipeline(channels));
    result.realize(out);

    delete[] in_buf;
    delete[] out_buf;
}

int main(int argc, char **argv) {
    copy_interleaved(true, 4);
    copy_interleaved(false, 4);
    copy_interleaved(true, 3);
    copy_interleaved(false, 3);

    std::cout << "Done!" << std::endl;
    return 0;
}
<commit_msg>Another using directive for renderscript jit copy test<commit_after>#include "Halide.h"

using namespace Halide;
using namespace Halide::Internal;

class ValidateInterleavedPipeline: public IRMutator {
protected:
//
// This is roughly the structure that we are trying to validate in this custom pass:
//
// parallel<Renderscript> (result$2.s0.y$2.__block_id_y, 0, result$2.extent.1) {
//   parallel<Renderscript> (result$2.s0.x$2.__block_id_x, 0, result$2.extent.0) {
//     ...
//     parallel<Renderscript> (.__thread_id_x, 0, 1) {
//       for<Renderscript> (result$2.s0.c$2, 0, 4) {
//         image_store("result$2",
//                     result$2.buffer,
//                     (result$2.s0.x$2.__block_id_x + result$2.min.0),
//                     (result$2.s0.y$2.__block_id_y + result$2.min.1),
//                     result$2.s0.c$2,
//                     image_load("input",
//                                input.buffer,
//                                ((result$2.s0.x$2.__block_id_x + result$2.min.0) - input.min.0),
//                                input.extent.0,
//                                ((result$2.s0.y$2.__block_id_y + result$2.min.1) - input.min.1),
//                                input.extent.1,
//                                result$2.s0.c$2,
//                                4))
//       }
//     }
//     ...
//   }
// }
//
    using IRMutator::visit;

    virtual void visit(const Call *call) {
        if (in_pipeline && call->call_type == Call::CallType::Intrinsic && call->name == Call::image_store) {
            assert(for_nest_level == 4);

            std::map<std::string, Expr> matches;

            assert(expr_match(
                StringImm::make("result"),
                call->args[0],
                matches));
            assert(expr_match(
                Variable::make(Handle(1), "result.buffer"),
                call->args[1],
                matches));
            assert(expr_match(
                Variable::make(Int(32), "result.s0.x.__block_id_x") + Variable::make(Int(32), "result.min.0"),
                call->args[2],
                matches));
            assert(expr_match(
                Variable::make(Int(32), "result.s0.y.__block_id_y") + Variable::make(Int(32), "result.min.1"),
                call->args[3],
                matches));
            assert(expr_match(
                Variable::make(Int(32), "result.s0.c"),
                call->args[4],
                matches));
            assert(expr_match(
                Call::make(
                    UInt(8),
                    Call::image_load,
                    {
                        StringImm::make("input"),
                        Variable::make(Handle(1), "input.buffer"),
                        (Variable::make(Int(32), "result.s0.x.__block_id_x") +
                            Variable::make(Int(32), "result.min.0")) -
                            Variable::make(Int(32), "input.min.0"),
                        Variable::make(Int(32), "input.extent.0"),
                        (Variable::make(Int(32), "result.s0.y.__block_id_y") +
                            Variable::make(Int(32), "result.min.1")) -
                            Variable::make(Int(32), "input.min.1"),
                        Variable::make(Int(32), "input.extent.1"),
                        Variable::make(Int(32), "result.s0.c"),
                        IntImm::make(channels)
                    },
                    Call::CallType::Intrinsic),
                call->args[5],
                matches));
        }
        IRMutator::visit(call);
    }

    void visit(const For *op) {
        if (in_pipeline) {
            assert(for_nest_level >= 0); // For-loop should show up in Pipeline.
            for_nest_level++;
            if (for_nest_level <= 3) {
                assert(op->for_type == ForType::Parallel);
            }
            assert(op->device_api == DeviceAPI::Renderscript);
        }
        IRMutator::visit(op);
    }

    void visit(const ProducerConsumer *op) {
        assert(!in_pipeline); // There should be only one pipeline in the test.
        for_nest_level = 0;
        in_pipeline = true;

        assert(op->produce.defined());
        assert(!op->update.defined());
        assert(op->consume.defined());

        IRMutator::visit(op);
        stmt = Stmt();
    }

    int for_nest_level = -1;
    bool in_pipeline = false;
    int channels;

public:
    ValidateInterleavedPipeline(int _channels) : channels(_channels) {}
};

class ValidateInterleavedVectorizedPipeline: public ValidateInterleavedPipeline {
    using IRMutator::visit;
    using ValidateInterleavedPipeline::visit;

    virtual void visit(const Call *call) {
        if (in_pipeline && call->call_type == Call::CallType::Intrinsic && call->name == Call::image_store) {
            assert(for_nest_level == 3); // Should be three nested for-loops before we get to the first call.

            std::map<std::string, Expr> matches;

            assert(expr_match(
                Broadcast::make(StringImm::make("result"), channels),
                call->args[0],
                matches));
            assert(expr_match(
                Broadcast::make(Variable::make(Handle(1), "result.buffer"), channels),
                call->args[1],
                matches));
            assert(expr_match(
                Broadcast::make(Variable::make(Int(32), "result.s0.x.__block_id_x") + Variable::make(Int(32), "result.min.0"), channels),
                call->args[2],
                matches));
            assert(expr_match(
                Broadcast::make(Variable::make(Int(32), "result.s0.y.__block_id_y") + Variable::make(Int(32), "result.min.1"), channels),
                call->args[3],
                matches));
            assert(expr_match(
                Ramp::make(0, 1, channels), call->args[4], matches));
            assert(expr_match(
                Call::make(
                    UInt(8, channels),
                    Call::image_load,
                    {
                        Broadcast::make(StringImm::make("input"), channels),
                        Broadcast::make(Variable::make(Handle(1), "input.buffer"), channels),
                        Broadcast::make(
                            Add::make(
                                Variable::make(Int(32), "result.s0.x.__block_id_x"),
                                Variable::make(Int(32), "result.min.0")) -
                            Variable::make(Int(32), "input.min.0"),
                            channels),
                        Broadcast::make(Variable::make(Int(32), "input.extent.0"), channels),
                        Broadcast::make(
                            Add::make(
                                Variable::make(Int(32), "result.s0.y.__block_id_y"),
                                Variable::make(Int(32), "result.min.1")) -
                            Variable::make(Int(32), "input.min.1"),
                            channels),
                        Broadcast::make(Variable::make(Int(32), "input.extent.1"), channels),
                        Ramp::make(0, 1, channels),
                        Broadcast::make(IntImm::make(channels), channels)
                    },
                    Call::CallType::Intrinsic),
                call->args[5],
                matches));
        }
        IRMutator::visit(call);
    }
public:
    ValidateInterleavedVectorizedPipeline(int _channels) : ValidateInterleavedPipeline(_channels) {}
};

Image<uint8_t> make_interleaved_image(uint8_t *host, int W, int H, int channels) {
    buffer_t buf = { 0 };
    buf.host = host;
    buf.extent[0] = W;
    buf.stride[0] = channels;
    buf.extent[1] = H;
    buf.stride[1] = buf.stride[0] * buf.extent[0];
    buf.extent[2] = channels;
    buf.stride[2] = 1;
    buf.elem_size = 1;
    return Image<uint8_t>(&buf);
}

void copy_interleaved(bool vectorized = false, int channels = 4) {
    ImageParam input8(UInt(8), 3, "input");
    input8.set_stride(0, channels)
        .set_stride(1, Halide::Expr())
        .set_stride(2, 1)
        .set_bounds(2, 0, channels);  // expecting interleaved image
    uint8_t *in_buf = new uint8_t[128 * 128 * channels];
    uint8_t *out_buf = new uint8_t[128 * 128 * channels];
    Image<uint8_t> in = make_interleaved_image(in_buf, 128, 128, channels);
    Image<uint8_t> out = make_interleaved_image(out_buf, 128, 128, channels);
    input8.set(in);

    Var x, y, c;
    Func result("result");
    result(x, y, c) = input8(x, y, c);
    result.output_buffer()
        .set_stride(0, channels)
        .set_stride(1, Halide::Expr())
        .set_stride(2, 1)
        .set_bounds(2, 0, channels);  // expecting interleaved image

    result.bound(c, 0, channels);
    result.shader(x, y, c, DeviceAPI::Renderscript);
    if (vectorized) result.vectorize(c);

    result.add_custom_lowering_pass(
        vectorized?
            new ValidateInterleavedVectorizedPipeline(channels):
            new ValidateInterleavedPipeline(channels));
    result.realize(out);

    delete[] in_buf;
    delete[] out_buf;
}

int main(int argc, char **argv) {
    copy_interleaved(true, 4);
    copy_interleaved(false, 4);
    copy_interleaved(true, 3);
    copy_interleaved(false, 3);

    std::cout << "Done!" << std::endl;
    return 0;
}
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkBinaryMinMaxCurvatureFlowImageFilterTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

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

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include "itkBinaryMinMaxCurvatureFlowImageFilter.h"
#include "itkOutputWindow.h"
#include "itkCommand.h"
#include "itkImage.h"
#include "itkImageRegionIterator.h"
#include "vnl/vnl_math.h"
#include "vnl/vnl_sample.h"
#include "vcl_ctime.h"

// The following class is used to support callbacks
// on the filter in the pipeline that follows later
namespace
{class ShowProgressObject
{
public:
  ShowProgressObject(itk::ProcessObject* o)
    {m_Process = o;}
  void ShowProgress()
    {std::cout << "Progress " << m_Process->GetProgress() << std::endl;}
  itk::ProcessObject::Pointer m_Process;
};
}

#define MAXRUNS 5 // maximum number of runs

template<unsigned int VImageDimension>
int testBinaryMinMaxCurvatureFlow(
  itk::Size<VImageDimension> & size,
  double threshold,
  double radius,
  int numberOfRuns,
  unsigned int niter[],
  unsigned long radii[] );

/**
 * This file tests the functionality of the BinaryMinMaxCurvatureFlowImageFilter.
 * The test uses a binary image of a circle/sphere with intensity value
 * of 0 (black). The background is white ( intensity = 255 ).
 * X% salt and pepper noise is added to the the input image. Specifically,
 * X% of the pixels is replaced with a value choosen from a uniform
 * distribution between 0 and 255.
 *
 * We then test the ability of BinaryMinMaxCurvatureFlowImageFilter to denoise
 * the binary image.
 */
int itkBinaryMinMaxCurvatureFlowImageFilterTest(int, char* [] )
{

  double radius;
  int numberOfRuns;
  unsigned int niter[MAXRUNS];
  unsigned long radii[MAXRUNS];

  itk::Size<2> size2D;
  size2D[0] = 64; size2D[1] = 64;
  radius = 20.0;
  numberOfRuns = 2;
  niter[0] = 100; niter[1] = 100;
  radii[0] = 1; radii[1] = 3;

  int err2D = testBinaryMinMaxCurvatureFlow( size2D, 127.5, radius, numberOfRuns,
    niter, radii );

  if ( err2D )
    {
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;

}

template<unsigned int VImageDimension>
int testBinaryMinMaxCurvatureFlow(
  itk::Size<VImageDimension> & size, // ND image size
  double threshold,
  double radius,                     // ND-sphere radius
  int numberOfRuns,                  // number of times to run the filter
  unsigned int niter[],              // number of iterations
  unsigned long radii[]              // stencil radius
)
{

  typedef float PixelType;
  enum { ImageDimension = VImageDimension };
  typedef itk::Image<PixelType, ImageDimension> ImageType;
  typedef itk::ImageRegionIterator<ImageType> IteratorType;
  typedef itk::BinaryMinMaxCurvatureFlowImageFilter<ImageType,ImageType> DenoiserType;
  typename DenoiserType::Pointer denoiser = DenoiserType::New();

  int j;

  /**
   * Create an image containing a circle/sphere with intensity of 0
   * and background of 255 with added salt and pepper noise.
   */
  double sqrRadius = vnl_math_sqr( radius );  // radius of the circle/sphere
  double fractionNoise = 0.30;              // salt & pepper noise fraction
  PixelType foreground = 0.0;               // intensity value of the foreground
  PixelType background = 255.0;             // intensity value of the background

  std::cout << "Create an image of circle/sphere with noise" << std::endl;
  typename ImageType::Pointer circleImage = ImageType::New();

  typename ImageType::RegionType region;
  region.SetSize( size );

  circleImage->SetLargestPossibleRegion( region );
  circleImage->SetBufferedRegion( region );
  circleImage->Allocate();

  IteratorType circleIter( circleImage, circleImage->GetBufferedRegion() );

  for ( ; !circleIter.IsAtEnd() ; ++circleIter )
    {
    typename ImageType::IndexType index = circleIter.GetIndex();
    float value;

    double lhs = 0.0;
    for ( j = 0; j < ImageDimension; j++ )
      {
      lhs += vnl_math_sqr( (double) index[j] - (double) size[j] * 0.5 );
      }
    if ( lhs < sqrRadius )
      {
      value = foreground;
      }
    else
      {
      value = background;
      }

    if ( vnl_sample_uniform( 0.0, 1.0 ) < fractionNoise )
      {
      value = vnl_sample_uniform( vnl_math_min(foreground,background),
        vnl_math_max(foreground,background) );
      }

    circleIter.Set( value );

    }

  /**
   * Run MinMaxCurvatureFlowImageFilter several times using the previous
   * output as the input in the next run.
   */

  std::cout << "Run BinaryMinMaxCurvatureFlowImageFiler.." << std::endl;

  // set other denoiser parameters here
  denoiser->SetTimeStep( 0.05 );
  denoiser->SetThreshold( threshold );

  // attach a progress watcher to the denoiser
  ShowProgressObject progressWatch(denoiser);
  itk::SimpleMemberCommand<ShowProgressObject>::Pointer command;
  command = itk::SimpleMemberCommand<ShowProgressObject>::New();
  command->SetCallbackFunction(&progressWatch,
                               &ShowProgressObject::ShowProgress);
  denoiser->AddObserver( itk::ProgressEvent(), command);

  typename ImageType::Pointer swapPointer = circleImage;

  for ( int j = 0; j < numberOfRuns; j++ )
    {

    denoiser->SetInput( swapPointer );

    // set the stencil radius and number of iterations
    denoiser->SetStencilRadius( radii[j] );
    denoiser->SetNumberOfIterations( niter[j] );

    std::cout << " Run: " << j;
    std::cout << " Radius: " << denoiser->GetStencilRadius();
    std::cout << " Iter: " << denoiser->GetNumberOfIterations();
    std::cout << std::endl;

    // run the filter
    denoiser->Update();

    swapPointer = denoiser->GetOutput();
    swapPointer->DisconnectPipeline();
    }

  /**
   * Check the quality of the output by comparing it against a
   * clean image of the circle/sphere.
   * An output pixel is okay if it is within
   * 0.1 * |foreground - background| of the true value.
   * This test is considered as passed if the fraction of wrong
   * pixels is less than the original noise fraction.
   */
  std::cout << "Checking the output..." << std::endl;

  IteratorType outIter( swapPointer,
    swapPointer->GetBufferedRegion() );

  PixelType tolerance = vnl_math_abs( foreground - background ) * 0.1;

  unsigned long numPixelsWrong = 0;

  for ( ; !outIter.IsAtEnd(); ++outIter )
    {

    typename ImageType::IndexType index = outIter.GetIndex();
    PixelType value = outIter.Get();

    double lhs = 0.0;
    for ( j = 0; j < ImageDimension; j++ )
      {
      lhs += vnl_math_sqr( (double) index[j] - (double) size[j] * 0.5 );
      }
    if ( lhs < sqrRadius )
      {
      if ( vnl_math_abs( foreground - value ) > tolerance )
        {
        numPixelsWrong++;
        }
      }
    else if ( vnl_math_abs( background - value ) > tolerance )
      {
      numPixelsWrong++;
      }
    }

  double fractionWrong = (double) numPixelsWrong /
    (double) region.GetNumberOfPixels();

  std::cout << "Noise reduced from " << fractionNoise << " to ";
  std::cout << fractionWrong << std::endl;

  bool passed = true;
  if ( fractionWrong > fractionNoise )
    {
    std::cout << "Test failed." << std::endl;
    return EXIT_FAILURE;
   }

  /**
   * Exercise other member functions here
   */
  denoiser->Print( std::cout );
  std::cout << "GetThreshold: " << denoiser->GetThreshold() << std::endl;

 /**
  * Exercise error handling
  */
  typedef itk::CurvatureFlowFunction<ImageType> WrongFunctionType;
  typename WrongFunctionType::Pointer wrongFunction = WrongFunctionType::New();

  passed = false;
  try
    {
    denoiser->SetDifferenceFunction( wrongFunction );
    denoiser->Update();
    }
  catch( itk::ExceptionObject& err )
    {
    passed = true;
    std::cout << "Caught expected exception." << std::endl;
    std::cout << err << std::endl;
    }

  if ( !passed )
    {
    std::cout << "Test failed." << std::endl;
    return EXIT_FAILURE;
    }

  std::cout << "Test passed." << std::endl;
  return EXIT_SUCCESS;

}
<commit_msg>BUG: If CYGWIN call vnl_sample_reseed<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkBinaryMinMaxCurvatureFlowImageFilterTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

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

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include "itkBinaryMinMaxCurvatureFlowImageFilter.h"
#include "itkOutputWindow.h"
#include "itkCommand.h"
#include "itkImage.h"
#include "itkImageRegionIterator.h"
#include "vnl/vnl_math.h"
#include "vnl/vnl_sample.h"
#include "vcl_ctime.h"

// The following class is used to support callbacks
// on the filter in the pipeline that follows later
namespace
{class ShowProgressObject
{
public:
  ShowProgressObject(itk::ProcessObject* o)
    {m_Process = o;}
  void ShowProgress()
    {std::cout << "Progress " << m_Process->GetProgress() << std::endl;}
  itk::ProcessObject::Pointer m_Process;
};
}

#define MAXRUNS 5 // maximum number of runs

template<unsigned int VImageDimension>
int testBinaryMinMaxCurvatureFlow(
  itk::Size<VImageDimension> & size,
  double threshold,
  double radius,
  int numberOfRuns,
  unsigned int niter[],
  unsigned long radii[] );

/**
 * This file tests the functionality of the BinaryMinMaxCurvatureFlowImageFilter.
 * The test uses a binary image of a circle/sphere with intensity value
 * of 0 (black). The background is white ( intensity = 255 ).
 * X% salt and pepper noise is added to the the input image. Specifically,
 * X% of the pixels is replaced with a value choosen from a uniform
 * distribution between 0 and 255.
 *
 * We then test the ability of BinaryMinMaxCurvatureFlowImageFilter to denoise
 * the binary image.
 */
int itkBinaryMinMaxCurvatureFlowImageFilterTest(int, char* [] )
{

  double radius;
  int numberOfRuns;
  unsigned int niter[MAXRUNS];
  unsigned long radii[MAXRUNS];

  itk::Size<2> size2D;
  size2D[0] = 64; size2D[1] = 64;
  radius = 20.0;
  numberOfRuns = 2;
  niter[0] = 100; niter[1] = 100;
  radii[0] = 1; radii[1] = 3;

#if __CYGWIN__
  vnl_sample_reseed(0x1234abcd);
#endif

  int err2D = testBinaryMinMaxCurvatureFlow( size2D, 127.5, radius, numberOfRuns,
    niter, radii );

  if ( err2D )
    {
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;

}

template<unsigned int VImageDimension>
int testBinaryMinMaxCurvatureFlow(
  itk::Size<VImageDimension> & size, // ND image size
  double threshold,
  double radius,                     // ND-sphere radius
  int numberOfRuns,                  // number of times to run the filter
  unsigned int niter[],              // number of iterations
  unsigned long radii[]              // stencil radius
)
{

  typedef float PixelType;
  enum { ImageDimension = VImageDimension };
  typedef itk::Image<PixelType, ImageDimension> ImageType;
  typedef itk::ImageRegionIterator<ImageType> IteratorType;
  typedef itk::BinaryMinMaxCurvatureFlowImageFilter<ImageType,ImageType> DenoiserType;
  typename DenoiserType::Pointer denoiser = DenoiserType::New();

  int j;

  /**
   * Create an image containing a circle/sphere with intensity of 0
   * and background of 255 with added salt and pepper noise.
   */
  double sqrRadius = vnl_math_sqr( radius );  // radius of the circle/sphere
  double fractionNoise = 0.30;              // salt & pepper noise fraction
  PixelType foreground = 0.0;               // intensity value of the foreground
  PixelType background = 255.0;             // intensity value of the background

  std::cout << "Create an image of circle/sphere with noise" << std::endl;
  typename ImageType::Pointer circleImage = ImageType::New();

  typename ImageType::RegionType region;
  region.SetSize( size );

  circleImage->SetLargestPossibleRegion( region );
  circleImage->SetBufferedRegion( region );
  circleImage->Allocate();

  IteratorType circleIter( circleImage, circleImage->GetBufferedRegion() );

  for ( ; !circleIter.IsAtEnd() ; ++circleIter )
    {
    typename ImageType::IndexType index = circleIter.GetIndex();
    float value;

    double lhs = 0.0;
    for ( j = 0; j < ImageDimension; j++ )
      {
      lhs += vnl_math_sqr( (double) index[j] - (double) size[j] * 0.5 );
      }
    if ( lhs < sqrRadius )
      {
      value = foreground;
      }
    else
      {
      value = background;
      }

    if ( vnl_sample_uniform( 0.0, 1.0 ) < fractionNoise )
      {
      value = vnl_sample_uniform( vnl_math_min(foreground,background),
        vnl_math_max(foreground,background) );
      }

    circleIter.Set( value );

    }

  /**
   * Run MinMaxCurvatureFlowImageFilter several times using the previous
   * output as the input in the next run.
   */

  std::cout << "Run BinaryMinMaxCurvatureFlowImageFiler.." << std::endl;

  // set other denoiser parameters here
  denoiser->SetTimeStep( 0.05 );
  denoiser->SetThreshold( threshold );

  // attach a progress watcher to the denoiser
  ShowProgressObject progressWatch(denoiser);
  itk::SimpleMemberCommand<ShowProgressObject>::Pointer command;
  command = itk::SimpleMemberCommand<ShowProgressObject>::New();
  command->SetCallbackFunction(&progressWatch,
                               &ShowProgressObject::ShowProgress);
  denoiser->AddObserver( itk::ProgressEvent(), command);

  typename ImageType::Pointer swapPointer = circleImage;

  for ( int j = 0; j < numberOfRuns; j++ )
    {

    denoiser->SetInput( swapPointer );

    // set the stencil radius and number of iterations
    denoiser->SetStencilRadius( radii[j] );
    denoiser->SetNumberOfIterations( niter[j] );

    std::cout << " Run: " << j;
    std::cout << " Radius: " << denoiser->GetStencilRadius();
    std::cout << " Iter: " << denoiser->GetNumberOfIterations();
    std::cout << std::endl;

    // run the filter
    denoiser->Update();

    swapPointer = denoiser->GetOutput();
    swapPointer->DisconnectPipeline();
    }

  /**
   * Check the quality of the output by comparing it against a
   * clean image of the circle/sphere.
   * An output pixel is okay if it is within
   * 0.1 * |foreground - background| of the true value.
   * This test is considered as passed if the fraction of wrong
   * pixels is less than the original noise fraction.
   */
  std::cout << "Checking the output..." << std::endl;

  IteratorType outIter( swapPointer,
    swapPointer->GetBufferedRegion() );

  PixelType tolerance = vnl_math_abs( foreground - background ) * 0.1;

  unsigned long numPixelsWrong = 0;

  for ( ; !outIter.IsAtEnd(); ++outIter )
    {

    typename ImageType::IndexType index = outIter.GetIndex();
    PixelType value = outIter.Get();

    double lhs = 0.0;
    for ( j = 0; j < ImageDimension; j++ )
      {
      lhs += vnl_math_sqr( (double) index[j] - (double) size[j] * 0.5 );
      }
    if ( lhs < sqrRadius )
      {
      if ( vnl_math_abs( foreground - value ) > tolerance )
        {
        numPixelsWrong++;
        }
      }
    else if ( vnl_math_abs( background - value ) > tolerance )
      {
      numPixelsWrong++;
      }
    }

  double fractionWrong = (double) numPixelsWrong /
    (double) region.GetNumberOfPixels();

  std::cout << "Noise reduced from " << fractionNoise << " to ";
  std::cout << fractionWrong << std::endl;

  bool passed = true;
  if ( fractionWrong > fractionNoise )
    {
    std::cout << "Test failed." << std::endl;
    return EXIT_FAILURE;
   }

  /**
   * Exercise other member functions here
   */
  denoiser->Print( std::cout );
  std::cout << "GetThreshold: " << denoiser->GetThreshold() << std::endl;

 /**
  * Exercise error handling
  */
  typedef itk::CurvatureFlowFunction<ImageType> WrongFunctionType;
  typename WrongFunctionType::Pointer wrongFunction = WrongFunctionType::New();

  passed = false;
  try
    {
    denoiser->SetDifferenceFunction( wrongFunction );
    denoiser->Update();
    }
  catch( itk::ExceptionObject& err )
    {
    passed = true;
    std::cout << "Caught expected exception." << std::endl;
    std::cout << err << std::endl;
    }

  if ( !passed )
    {
    std::cout << "Test failed." << std::endl;
    return EXIT_FAILURE;
    }

  std::cout << "Test passed." << std::endl;
  return EXIT_SUCCESS;

}
<|endoftext|>


<commit_before>//===- bugpoint.cpp - The LLVM Bugpoint utility ---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program is an automated compiler debugger tool.  It is used to narrow
// down miscompilations and crash problems to a specific pass in the compiler,
// and the specific Module or Function input that is causing the problem.
//
//===----------------------------------------------------------------------===//

#include "BugDriver.h"
#include "ToolRunner.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/LLVMContext.h"
#include "llvm/Support/PassNameParser.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/StandardPasses.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/Valgrind.h"
#include "llvm/LinkAllVMCore.h"
using namespace llvm;

static cl::opt<bool>
FindBugs("find-bugs", cl::desc("Run many different optimization sequences "
                               "on program to find bugs"), cl::init(false));

static cl::list<std::string>
InputFilenames(cl::Positional, cl::OneOrMore,
               cl::desc("<input llvm ll/bc files>"));

static cl::opt<unsigned>
TimeoutValue("timeout", cl::init(300), cl::value_desc("seconds"),
             cl::desc("Number of seconds program is allowed to run before it "
                      "is killed (default is 300s), 0 disables timeout"));

static cl::opt<int>
MemoryLimit("mlimit", cl::init(-1), cl::value_desc("MBytes"),
             cl::desc("Maximum amount of memory to use. 0 disables check."
                      " Defaults to 100MB (800MB under valgrind)."));

static cl::opt<bool>
UseValgrind("enable-valgrind",
            cl::desc("Run optimizations through valgrind"));

// The AnalysesList is automatically populated with registered Passes by the
// PassNameParser.
//
static cl::list<const PassInfo*, bool, PassNameParser>
PassList(cl::desc("Passes available:"), cl::ZeroOrMore);

static cl::opt<bool>
StandardCompileOpts("std-compile-opts",
                   cl::desc("Include the standard compile time optimizations"));

static cl::opt<bool>
StandardLinkOpts("std-link-opts",
                 cl::desc("Include the standard link time optimizations"));

static cl::opt<std::string>
OverrideTriple("mtriple", cl::desc("Override target triple for module"));

/// BugpointIsInterrupted - Set to true when the user presses ctrl-c.
bool llvm::BugpointIsInterrupted = false;

static void BugpointInterruptFunction() {
  BugpointIsInterrupted = true;
}

// Hack to capture a pass list.
namespace {
  class AddToDriver : public PassManager {
    BugDriver &D;
  public:
    AddToDriver(BugDriver &_D) : D(_D) {}

    virtual void add(Pass *P) {
      const void *ID = P->getPassID();
      const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(ID);
      D.addPass(PI->getPassArgument());
    }
  };
}

int main(int argc, char **argv) {
  llvm::sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram X(argc, argv);
  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.

  // Initialize passes
  PassRegistry &Registry = *PassRegistry::getPassRegistry();
  initializeCore(Registry);
  initializeScalarOpts(Registry);
  initializeIPO(Registry);
  initializeAnalysis(Registry);
  initializeIPA(Registry);
  initializeTransformUtils(Registry);
  initializeInstCombine(Registry);
  initializeInstrumentation(Registry);
  initializeTarget(Registry);

  cl::ParseCommandLineOptions(argc, argv,
                              "LLVM automatic testcase reducer. See\nhttp://"
                              "llvm.org/cmds/bugpoint.html"
                              " for more information.\n");
  sys::SetInterruptFunction(BugpointInterruptFunction);

  LLVMContext& Context = getGlobalContext();
  // If we have an override, set it and then track the triple we want Modules
  // to use.
  if (!OverrideTriple.empty()) {
    TargetTriple.setTriple(Triple::normalize(OverrideTriple));
    outs() << "Override triple set to '" << TargetTriple.getTriple() << "'\n";
  }

  if (MemoryLimit < 0) {
    // Set the default MemoryLimit.  Be sure to update the flag's description if
    // you change this.
    if (sys::RunningOnValgrind() || UseValgrind)
      MemoryLimit = 800;
    else
      MemoryLimit = 100;
  }

  BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit,
              UseValgrind, Context);
  if (D.addSources(InputFilenames)) return 1;

  AddToDriver PM(D);
  if (StandardCompileOpts) {
    createStandardModulePasses(&PM, 3,
                               /*OptimizeSize=*/ false,
                               /*UnitAtATime=*/ true,
                               /*UnrollLoops=*/ true,
                               /*SimplifyLibCalls=*/ true,
                               /*HaveExceptions=*/ true,
                               createFunctionInliningPass());
  }

  if (StandardLinkOpts)
    createStandardLTOPasses(&PM, /*Internalize=*/true,
                            /*RunInliner=*/true,
                            /*VerifyEach=*/false);

  for (std::vector<const PassInfo*>::iterator I = PassList.begin(),
         E = PassList.end();
       I != E; ++I) {
    const PassInfo* PI = *I;
    D.addPass(PI->getPassArgument());
  }

  // Bugpoint has the ability of generating a plethora of core files, so to
  // avoid filling up the disk, we prevent it
  sys::Process::PreventCoreFiles();

  std::string Error;
  bool Failure = D.run(Error);
  if (!Error.empty()) {
    errs() << Error;
    return 1;
  }
  return Failure;
}
<commit_msg>Little help to debug the bugpoint itself. Patch by Bob Wilson.<commit_after>//===- bugpoint.cpp - The LLVM Bugpoint utility ---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program is an automated compiler debugger tool.  It is used to narrow
// down miscompilations and crash problems to a specific pass in the compiler,
// and the specific Module or Function input that is causing the problem.
//
//===----------------------------------------------------------------------===//

#include "BugDriver.h"
#include "ToolRunner.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/LLVMContext.h"
#include "llvm/Support/PassNameParser.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/StandardPasses.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/Valgrind.h"
#include "llvm/LinkAllVMCore.h"

// Enable this macro to debug bugpoint itself.
#define DEBUG_BUGPOINT 0

using namespace llvm;

static cl::opt<bool>
FindBugs("find-bugs", cl::desc("Run many different optimization sequences "
                               "on program to find bugs"), cl::init(false));

static cl::list<std::string>
InputFilenames(cl::Positional, cl::OneOrMore,
               cl::desc("<input llvm ll/bc files>"));

static cl::opt<unsigned>
TimeoutValue("timeout", cl::init(300), cl::value_desc("seconds"),
             cl::desc("Number of seconds program is allowed to run before it "
                      "is killed (default is 300s), 0 disables timeout"));

static cl::opt<int>
MemoryLimit("mlimit", cl::init(-1), cl::value_desc("MBytes"),
             cl::desc("Maximum amount of memory to use. 0 disables check."
                      " Defaults to 100MB (800MB under valgrind)."));

static cl::opt<bool>
UseValgrind("enable-valgrind",
            cl::desc("Run optimizations through valgrind"));

// The AnalysesList is automatically populated with registered Passes by the
// PassNameParser.
//
static cl::list<const PassInfo*, bool, PassNameParser>
PassList(cl::desc("Passes available:"), cl::ZeroOrMore);

static cl::opt<bool>
StandardCompileOpts("std-compile-opts",
                   cl::desc("Include the standard compile time optimizations"));

static cl::opt<bool>
StandardLinkOpts("std-link-opts",
                 cl::desc("Include the standard link time optimizations"));

static cl::opt<std::string>
OverrideTriple("mtriple", cl::desc("Override target triple for module"));

/// BugpointIsInterrupted - Set to true when the user presses ctrl-c.
bool llvm::BugpointIsInterrupted = false;

#ifndef DEBUG_BUGPOINT
static void BugpointInterruptFunction() {
  BugpointIsInterrupted = true;
}
#endif

// Hack to capture a pass list.
namespace {
  class AddToDriver : public PassManager {
    BugDriver &D;
  public:
    AddToDriver(BugDriver &_D) : D(_D) {}

    virtual void add(Pass *P) {
      const void *ID = P->getPassID();
      const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(ID);
      D.addPass(PI->getPassArgument());
    }
  };
}

int main(int argc, char **argv) {
#ifndef DEBUG_BUGPOINT
  llvm::sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram X(argc, argv);
  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
#endif

  // Initialize passes
  PassRegistry &Registry = *PassRegistry::getPassRegistry();
  initializeCore(Registry);
  initializeScalarOpts(Registry);
  initializeIPO(Registry);
  initializeAnalysis(Registry);
  initializeIPA(Registry);
  initializeTransformUtils(Registry);
  initializeInstCombine(Registry);
  initializeInstrumentation(Registry);
  initializeTarget(Registry);

  cl::ParseCommandLineOptions(argc, argv,
                              "LLVM automatic testcase reducer. See\nhttp://"
                              "llvm.org/cmds/bugpoint.html"
                              " for more information.\n");
#ifndef DEBUG_BUGPOINT
  sys::SetInterruptFunction(BugpointInterruptFunction);
#endif

  LLVMContext& Context = getGlobalContext();
  // If we have an override, set it and then track the triple we want Modules
  // to use.
  if (!OverrideTriple.empty()) {
    TargetTriple.setTriple(Triple::normalize(OverrideTriple));
    outs() << "Override triple set to '" << TargetTriple.getTriple() << "'\n";
  }

  if (MemoryLimit < 0) {
    // Set the default MemoryLimit.  Be sure to update the flag's description if
    // you change this.
    if (sys::RunningOnValgrind() || UseValgrind)
      MemoryLimit = 800;
    else
      MemoryLimit = 100;
  }

  BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit,
              UseValgrind, Context);
  if (D.addSources(InputFilenames)) return 1;

  AddToDriver PM(D);
  if (StandardCompileOpts) {
    createStandardModulePasses(&PM, 3,
                               /*OptimizeSize=*/ false,
                               /*UnitAtATime=*/ true,
                               /*UnrollLoops=*/ true,
                               /*SimplifyLibCalls=*/ true,
                               /*HaveExceptions=*/ true,
                               createFunctionInliningPass());
  }

  if (StandardLinkOpts)
    createStandardLTOPasses(&PM, /*Internalize=*/true,
                            /*RunInliner=*/true,
                            /*VerifyEach=*/false);

  for (std::vector<const PassInfo*>::iterator I = PassList.begin(),
         E = PassList.end();
       I != E; ++I) {
    const PassInfo* PI = *I;
    D.addPass(PI->getPassArgument());
  }

  // Bugpoint has the ability of generating a plethora of core files, so to
  // avoid filling up the disk, we prevent it
#ifndef DEBUG_BUGPOINT
  sys::Process::PreventCoreFiles();
#endif

  std::string Error;
  bool Failure = D.run(Error);
  if (!Error.empty()) {
    errs() << Error;
    return 1;
  }
  return Failure;
}
<|endoftext|>


<commit_before>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <iterator>

#include <fc/io/json.hpp>
#include <fc/io/stdio.hpp>
#include <fc/network/http/websocket.hpp>
#include <fc/rpc/cli.hpp>
#include <fc/rpc/websocket_api.hpp>

#include <bts/app/api.hpp>
#include <bts/chain/address.hpp>
#include <bts/utilities/key_conversion.hpp>

using namespace bts::app;
using namespace bts::chain;
using namespace bts::utilities;
using namespace std;

struct wallet_data
{
   flat_set<account_id_type> accounts;
   // map of key_id -> base58 private key
   map<key_id_type, string>  keys;
   // map of account_name -> base58_private_key for
   //    incomplete account regs
   map<string, string> pending_account_registrations;

   string                    ws_server = "ws://localhost:8090";
   string                    ws_user;
   string                    ws_password;
};
FC_REFLECT( wallet_data, (accounts)(keys)(pending_account_registrations)(ws_server)(ws_user)(ws_password) );

/**
 *  This wallet assumes nothing about where the database server is
 *  located and performs minimal caching.  This API could be provided
 *  locally to be used by a web interface.
 */
class wallet_api
{
   public:
      wallet_api( fc::api<login_api> rapi )
      :_remote_api(rapi)
      {
         _remote_db  = _remote_api->database();
         _remote_net = _remote_api->network();
      }
      string  help()const;

      string  suggest_brain_key()const
      {
        return string("dummy");
      }
      variant get_object( object_id_type id )
      {
         return _remote_db->get_objects({id});
      }
      account_object get_account( string account_name_or_id )
      {
         FC_ASSERT( account_name_or_id.size() > 0 );
         vector<optional<account_object>> opt_account;
         if( std::isdigit( account_name_or_id.front() ) )
            opt_account = _remote_db->get_accounts( {fc::variant(account_name_or_id).as<account_id_type>()} );
         else
            opt_account = _remote_db->lookup_account_names( {account_name_or_id} );
         FC_ASSERT( opt_account.size() && opt_account.front() );
         return *opt_account.front();
      }

      bool import_key( string account_name_or_id, string wif_key )
      {
         auto opt_priv_key = wif_to_key(wif_key);
         FC_ASSERT( opt_priv_key.valid() );
         bts::chain::address wif_key_address = bts::chain::address(
             opt_priv_key->get_public_key() );

         auto acnt = get_account( account_name_or_id );

         flat_set<key_id_type> keys;
         for( auto item : acnt.active.auths )
         {
             if( item.first.type() == key_object_type )
                keys.insert( item.first );
         }
         for( auto item : acnt.owner.auths )
         {
             if( item.first.type() == key_object_type )
                keys.insert( item.first );
         }
         auto opt_keys = _remote_db->get_keys( vector<key_id_type>(keys.begin(),keys.end()) );
         for( const fc::optional<key_object>& opt_key : opt_keys )
         {
            // the requested key ID's should all exist because they are
            //    keys for an account
            FC_ASSERT( opt_key.valid() );
            // we do this check by address because key objects on the
            //    blockchain may not contain a key (i.e. are simply an address)
            if( opt_key->key_address() == wif_key_address )
            {
               _wallet.keys[ opt_key->id ] = wif_key;
               return true;
            }
         }
         ilog( "key not for account ${name}", ("name",account_name_or_id) );
         return false;
      }

      string normalize_brain_key( string s )
      {
          size_t i = 0, n = s.length();
          std::string result;
          char c;
          result.reserve( n );

          bool preceded_by_whitespace = false;
          bool non_empty = false;
          while( i < n )
          {
              c = s[i++];
              switch( c )
              {
                  case ' ':  case '\t': case '\r': case '\n': case '\v': case '\f':
                      preceded_by_whitespace = true;
                      continue;

                  case 'a': c = 'A'; break;
                  case 'b': c = 'B'; break;
                  case 'c': c = 'C'; break;
                  case 'd': c = 'D'; break;
                  case 'e': c = 'E'; break;
                  case 'f': c = 'F'; break;
                  case 'g': c = 'G'; break;
                  case 'h': c = 'H'; break;
                  case 'i': c = 'I'; break;
                  case 'j': c = 'J'; break;
                  case 'k': c = 'K'; break;
                  case 'l': c = 'L'; break;
                  case 'm': c = 'M'; break;
                  case 'n': c = 'N'; break;
                  case 'o': c = 'O'; break;
                  case 'p': c = 'P'; break;
                  case 'q': c = 'Q'; break;
                  case 'r': c = 'R'; break;
                  case 's': c = 'S'; break;
                  case 't': c = 'T'; break;
                  case 'u': c = 'U'; break;
                  case 'v': c = 'V'; break;
                  case 'w': c = 'W'; break;
                  case 'x': c = 'X'; break;
                  case 'y': c = 'Y'; break;
                  case 'z': c = 'Z'; break;

                  default:
                      break;
              }
              if( preceded_by_whitespace && non_empty )
                  result.push_back(' ');
              result.push_back(c);
              preceded_by_whitespace = false;
              non_empty = true;
          }

          return result;
      }

      fc::ecc::private_key derive_private_key(
          const std::string& prefix_string, int sequence_number)
      {
           std::string sequence_string = std::to_string(sequence_number);
           fc::sha512 h = fc::sha512::hash(prefix_string + " " + sequence_string);
           fc::ecc::private_key derived_key = fc::ecc::private_key::regenerate(fc::sha256::hash(h));
           return derived_key;
      }

      signed_transaction create_account_with_brain_key(
          string brain_key,
          string account_name,
          string registrar_account,
          string referrer_account,
          uint8_t referrer_percent
          )
      {
        string normalized_brain_key = normalize_brain_key( brain_key );
        // TODO:  scan blockchain for accounts that exist with same brain key
        fc::ecc::private_key owner_privkey = derive_private_key( normalized_brain_key, 0 );
        fc::ecc::private_key active_privkey = derive_private_key( key_to_wif(owner_privkey), 0);

        bts::chain::public_key_type owner_pubkey = owner_privkey.get_public_key();
        bts::chain::public_key_type active_pubkey = active_privkey.get_public_key();

        account_create_operation account_create_op;

        // TODO:  process when pay_from_account is ID

        account_object registrar_account_object =
            this->get_account( registrar_account );

        account_id_type registrar_account_id = registrar_account_object.id;

        if( referrer_percent > 0 )
        {
            account_object referrer_account_object =
                this->get_account( referrer_account );
            account_create_op.referrer = referrer_account_object.id;
            account_create_op.referrer_percent = referrer_percent;
        }

        // get pay_from_account_id
        key_create_operation owner_key_create_op;
        owner_key_create_op.fee_paying_account = registrar_account_id;
        owner_key_create_op.key_data = owner_pubkey;

        key_create_operation active_key_create_op;
        active_key_create_op.fee_paying_account = registrar_account_id;
        active_key_create_op.key_data = active_pubkey;

        // key_create_op.calculate_fee(db.current_fee_schedule());

        // TODO:  Check if keys already exist!!!

        account_create_operation account_create_op;

        vector<string> v_pay_from_account;
        v_pay_from_account.push_back( pay_from_account );

        account_create_op.registrar = pay_from_account_id;

        relative_key_id_type owner_rkid(0);
        relative_key_id_type active_rkid(1);

        account_create_op.registrar = registrar_account_id;
        account_create_op.name = account_name;
        account_create_op.owner = authority(1, owner_rkid, 1);
        account_create_op.active = authority(1, active_rkid, 1);
        account_create_op.memo_key = active_rkid;
        account_create_op.voting_key = active_rkid;
        account_create_op.vote = flat_set<vote_tally_id_type>();

        // current_fee_schedule()
        // find_account(pay_from_account)

        // account_create_op.fee = account_create_op.calculate_fee(db.current_fee_schedule());

        signed_transaction tx;

        tx.operations.push_back( owner_key_create_op );
        tx.operations.push_back( active_key_create_op );
        tx.operations.push_back( account_create_op );

        tx.visit( operation_set_fee( _remote_db->get_global_properties().parameters.current_fees ) );

        vector<key_id_type> paying_keys = registrar_account_object.active.get_keys();

        tx.validate();

        for( key_id_type& key : paying_keys )
        {
            auto it = _wallet.keys.find(key);
            if( it != _wallet.keys.end() )
            {
                fc::optional< fc::ecc::private_key > privkey = wif_to_key( it->second );
                if( !privkey.valid() )
                {
                    FC_ASSERT( false, "Malformed private key in _wallet.keys" );
                }
                tx.sign( *privkey );
            }
        }

        // we do not insert owner_privkey here because
        //    it is intended to only be used for key recovery
        _wallet.pending_account_registrations[ account_name ] = key_to_wif( active_privkey );

        return tx;
      }

      signed_transaction transfer( string from,
                                   string to,
                                   uint64_t amount,
                                   string asset_symbol,
                                   string memo,
                                   bool broadcast = false )
      {
        auto opt_asset = _remote_db->lookup_asset_symbols( {asset_symbol} );
        wdump( (opt_asset) );
        return signed_transaction();
      }

      // methods that start with underscore are not incuded in API
      void _resync()
      {
         // this method is used to update wallet_data annotations
         //   e.g. wallet has been restarted and was not notified
         //   of events while it was down
         //
         // everything that is done "incremental style" when a push
         //   notification is received, should also be done here
         //   "batch style" by querying the blockchain

         if( _wallet.pending_account_registrations.size() > 0 )
         {
            std::vector<string> v_names;
            v_names.reserve( _wallet.pending_account_registrations.size() );

            for( auto it : _wallet.pending_account_registrations )
               v_names.push_back( it.first );

            std::vector< fc::optional< bts::chain::account_object >>
                v_accounts = _remote_db->lookup_account_names( v_names );

            for( fc::optional< bts::chain::account_object > opt_account : v_accounts )
            {
               if( ! opt_account.valid() )
                  continue;

               string account_name = opt_account->name;
               auto it = _wallet.pending_account_registrations.find( account_name );
               FC_ASSERT( it != _wallet.pending_account_registrations.end() );
               if( import_key( account_name, it->second ) )
               {
                  // somebody else beat our pending registration, there is
                  //    nothing we can do except log it and move on
                  ilog( "account ${name} registered by someone else first!",
                        ("name", account_name) );
                  // might as well remove it from pending regs,
                  //    because there is now no way this registration
                  //    can become valid (even in the extremely rare
                  //    possibility of migrating to a fork where the
                  //    name is available, the user can always
                  //    manually re-register)
               }
               _wallet.pending_account_registrations.erase( it );
            }
         }

         return;
      }

      wallet_data             _wallet;
      fc::api<login_api>      _remote_api;
      fc::api<database_api>   _remote_db;
      fc::api<network_api>    _remote_net;
};

FC_API( wallet_api,
        (help)
        (import_key)
        (suggest_brain_key)
        (create_account_with_brain_key)
        (transfer)
        (get_account)
        (get_object)
        (normalize_brain_key)
       )

struct help_visitor
{
   help_visitor( std::stringstream& s ):ss(s){}
   std::stringstream& ss;
   template<typename R, typename... Args>
   void operator()( const char* name, std::function<R(Args...)>& memb )const {
      ss << std::setw(40) << std::left << fc::get_typename<R>::name() << " " << name << "( ";
      vector<string> args{ fc::get_typename<Args>::name()... };
      for( uint32_t i = 0; i < args.size(); ++i )
         ss << args[i] << (i==args.size()-1?" ":", ");
      ss << ")\n";
   }

};
string  wallet_api::help()const
{
   fc::api<wallet_api> tmp;
   std::stringstream ss;
   tmp->visit( help_visitor(ss) );
   return ss.str();
}

int main( int argc, char** argv )
{
   try {
      FC_ASSERT( argc > 1, "usage: ${cmd} WALLET_FILE", ("cmd",argv[0]) );

      fc::ecc::private_key genesis_private_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("genesis")));
      idump( (key_to_wif( genesis_private_key ) ) );
      idump( (account_id_type()) );

      wallet_data wallet;
      fc::path wallet_file(argv[1]);
      if( fc::exists( wallet_file ) )
          wallet = fc::json::from_file( wallet_file ).as<wallet_data>();

      fc::http::websocket_client client;
      auto con  = client.connect( wallet.ws_server );
      auto apic = std::make_shared<fc::rpc::websocket_api_connection>(*con);
      con->closed.connect( [&](){ elog( "connection closed" ); } );

      auto remote_api = apic->get_remote_api< login_api >();
      FC_ASSERT( remote_api->login( wallet.ws_user, wallet.ws_password ) );

      auto wapiptr = std::make_shared<wallet_api>(remote_api);
      wapiptr->_wallet = wallet;

      fc::api<wallet_api> wapi(wapiptr);

      auto wallet_cli = std::make_shared<fc::rpc::cli>();
      wallet_cli->format_result( "help", [&]( variant result, const fc::variants& a) {
                                    return result.get_string();
                                });
      wallet_cli->register_api( wapi );
      wallet_cli->start();
      wallet_cli->wait();
   }
   catch ( const fc::exception& e )
   {
      std::cout << e.to_detail_string() << "\n";
   }
   return -1;
}
<commit_msg>remove vestigial code, it should compile now<commit_after>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <iterator>

#include <fc/io/json.hpp>
#include <fc/io/stdio.hpp>
#include <fc/network/http/websocket.hpp>
#include <fc/rpc/cli.hpp>
#include <fc/rpc/websocket_api.hpp>

#include <bts/app/api.hpp>
#include <bts/chain/address.hpp>
#include <bts/utilities/key_conversion.hpp>

using namespace bts::app;
using namespace bts::chain;
using namespace bts::utilities;
using namespace std;

struct wallet_data
{
   flat_set<account_id_type> accounts;
   // map of key_id -> base58 private key
   map<key_id_type, string>  keys;
   // map of account_name -> base58_private_key for
   //    incomplete account regs
   map<string, string> pending_account_registrations;

   string                    ws_server = "ws://localhost:8090";
   string                    ws_user;
   string                    ws_password;
};
FC_REFLECT( wallet_data, (accounts)(keys)(pending_account_registrations)(ws_server)(ws_user)(ws_password) );

/**
 *  This wallet assumes nothing about where the database server is
 *  located and performs minimal caching.  This API could be provided
 *  locally to be used by a web interface.
 */
class wallet_api
{
   public:
      wallet_api( fc::api<login_api> rapi )
      :_remote_api(rapi)
      {
         _remote_db  = _remote_api->database();
         _remote_net = _remote_api->network();
      }
      string  help()const;

      string  suggest_brain_key()const
      {
        return string("dummy");
      }
      variant get_object( object_id_type id )
      {
         return _remote_db->get_objects({id});
      }
      account_object get_account( string account_name_or_id )
      {
         FC_ASSERT( account_name_or_id.size() > 0 );
         vector<optional<account_object>> opt_account;
         if( std::isdigit( account_name_or_id.front() ) )
            opt_account = _remote_db->get_accounts( {fc::variant(account_name_or_id).as<account_id_type>()} );
         else
            opt_account = _remote_db->lookup_account_names( {account_name_or_id} );
         FC_ASSERT( opt_account.size() && opt_account.front() );
         return *opt_account.front();
      }

      bool import_key( string account_name_or_id, string wif_key )
      {
         auto opt_priv_key = wif_to_key(wif_key);
         FC_ASSERT( opt_priv_key.valid() );
         bts::chain::address wif_key_address = bts::chain::address(
             opt_priv_key->get_public_key() );

         auto acnt = get_account( account_name_or_id );

         flat_set<key_id_type> keys;
         for( auto item : acnt.active.auths )
         {
             if( item.first.type() == key_object_type )
                keys.insert( item.first );
         }
         for( auto item : acnt.owner.auths )
         {
             if( item.first.type() == key_object_type )
                keys.insert( item.first );
         }
         auto opt_keys = _remote_db->get_keys( vector<key_id_type>(keys.begin(),keys.end()) );
         for( const fc::optional<key_object>& opt_key : opt_keys )
         {
            // the requested key ID's should all exist because they are
            //    keys for an account
            FC_ASSERT( opt_key.valid() );
            // we do this check by address because key objects on the
            //    blockchain may not contain a key (i.e. are simply an address)
            if( opt_key->key_address() == wif_key_address )
            {
               _wallet.keys[ opt_key->id ] = wif_key;
               return true;
            }
         }
         ilog( "key not for account ${name}", ("name",account_name_or_id) );
         return false;
      }

      string normalize_brain_key( string s )
      {
          size_t i = 0, n = s.length();
          std::string result;
          char c;
          result.reserve( n );

          bool preceded_by_whitespace = false;
          bool non_empty = false;
          while( i < n )
          {
              c = s[i++];
              switch( c )
              {
                  case ' ':  case '\t': case '\r': case '\n': case '\v': case '\f':
                      preceded_by_whitespace = true;
                      continue;

                  case 'a': c = 'A'; break;
                  case 'b': c = 'B'; break;
                  case 'c': c = 'C'; break;
                  case 'd': c = 'D'; break;
                  case 'e': c = 'E'; break;
                  case 'f': c = 'F'; break;
                  case 'g': c = 'G'; break;
                  case 'h': c = 'H'; break;
                  case 'i': c = 'I'; break;
                  case 'j': c = 'J'; break;
                  case 'k': c = 'K'; break;
                  case 'l': c = 'L'; break;
                  case 'm': c = 'M'; break;
                  case 'n': c = 'N'; break;
                  case 'o': c = 'O'; break;
                  case 'p': c = 'P'; break;
                  case 'q': c = 'Q'; break;
                  case 'r': c = 'R'; break;
                  case 's': c = 'S'; break;
                  case 't': c = 'T'; break;
                  case 'u': c = 'U'; break;
                  case 'v': c = 'V'; break;
                  case 'w': c = 'W'; break;
                  case 'x': c = 'X'; break;
                  case 'y': c = 'Y'; break;
                  case 'z': c = 'Z'; break;

                  default:
                      break;
              }
              if( preceded_by_whitespace && non_empty )
                  result.push_back(' ');
              result.push_back(c);
              preceded_by_whitespace = false;
              non_empty = true;
          }

          return result;
      }

      fc::ecc::private_key derive_private_key(
          const std::string& prefix_string, int sequence_number)
      {
           std::string sequence_string = std::to_string(sequence_number);
           fc::sha512 h = fc::sha512::hash(prefix_string + " " + sequence_string);
           fc::ecc::private_key derived_key = fc::ecc::private_key::regenerate(fc::sha256::hash(h));
           return derived_key;
      }

      signed_transaction create_account_with_brain_key(
          string brain_key,
          string account_name,
          string registrar_account,
          string referrer_account,
          uint8_t referrer_percent
          )
      {
        string normalized_brain_key = normalize_brain_key( brain_key );
        // TODO:  scan blockchain for accounts that exist with same brain key
        fc::ecc::private_key owner_privkey = derive_private_key( normalized_brain_key, 0 );
        fc::ecc::private_key active_privkey = derive_private_key( key_to_wif(owner_privkey), 0);

        bts::chain::public_key_type owner_pubkey = owner_privkey.get_public_key();
        bts::chain::public_key_type active_pubkey = active_privkey.get_public_key();

        account_create_operation account_create_op;

        // TODO:  process when pay_from_account is ID

        account_object registrar_account_object =
            this->get_account( registrar_account );

        account_id_type registrar_account_id = registrar_account_object.id;

        if( referrer_percent > 0 )
        {
            account_object referrer_account_object =
                this->get_account( referrer_account );
            account_create_op.referrer = referrer_account_object.id;
            account_create_op.referrer_percent = referrer_percent;
        }

        // get pay_from_account_id
        key_create_operation owner_key_create_op;
        owner_key_create_op.fee_paying_account = registrar_account_id;
        owner_key_create_op.key_data = owner_pubkey;

        key_create_operation active_key_create_op;
        active_key_create_op.fee_paying_account = registrar_account_id;
        active_key_create_op.key_data = active_pubkey;

        // key_create_op.calculate_fee(db.current_fee_schedule());

        // TODO:  Check if keys already exist!!!

        relative_key_id_type owner_rkid(0);
        relative_key_id_type active_rkid(1);

        account_create_op.registrar = registrar_account_id;
        account_create_op.name = account_name;
        account_create_op.owner = authority(1, owner_rkid, 1);
        account_create_op.active = authority(1, active_rkid, 1);
        account_create_op.memo_key = active_rkid;
        account_create_op.voting_key = active_rkid;
        account_create_op.vote = flat_set<vote_tally_id_type>();

        // current_fee_schedule()
        // find_account(pay_from_account)

        // account_create_op.fee = account_create_op.calculate_fee(db.current_fee_schedule());

        signed_transaction tx;

        tx.operations.push_back( owner_key_create_op );
        tx.operations.push_back( active_key_create_op );
        tx.operations.push_back( account_create_op );

        tx.visit( operation_set_fee( _remote_db->get_global_properties().parameters.current_fees ) );

        vector<key_id_type> paying_keys = registrar_account_object.active.get_keys();

        tx.validate();

        for( key_id_type& key : paying_keys )
        {
            auto it = _wallet.keys.find(key);
            if( it != _wallet.keys.end() )
            {
                fc::optional< fc::ecc::private_key > privkey = wif_to_key( it->second );
                if( !privkey.valid() )
                {
                    FC_ASSERT( false, "Malformed private key in _wallet.keys" );
                }
                tx.sign( *privkey );
            }
        }

        // we do not insert owner_privkey here because
        //    it is intended to only be used for key recovery
        _wallet.pending_account_registrations[ account_name ] = key_to_wif( active_privkey );

        return tx;
      }

      signed_transaction transfer( string from,
                                   string to,
                                   uint64_t amount,
                                   string asset_symbol,
                                   string memo,
                                   bool broadcast = false )
      {
        auto opt_asset = _remote_db->lookup_asset_symbols( {asset_symbol} );
        wdump( (opt_asset) );
        return signed_transaction();
      }

      // methods that start with underscore are not incuded in API
      void _resync()
      {
         // this method is used to update wallet_data annotations
         //   e.g. wallet has been restarted and was not notified
         //   of events while it was down
         //
         // everything that is done "incremental style" when a push
         //   notification is received, should also be done here
         //   "batch style" by querying the blockchain

         if( _wallet.pending_account_registrations.size() > 0 )
         {
            std::vector<string> v_names;
            v_names.reserve( _wallet.pending_account_registrations.size() );

            for( auto it : _wallet.pending_account_registrations )
               v_names.push_back( it.first );

            std::vector< fc::optional< bts::chain::account_object >>
                v_accounts = _remote_db->lookup_account_names( v_names );

            for( fc::optional< bts::chain::account_object > opt_account : v_accounts )
            {
               if( ! opt_account.valid() )
                  continue;

               string account_name = opt_account->name;
               auto it = _wallet.pending_account_registrations.find( account_name );
               FC_ASSERT( it != _wallet.pending_account_registrations.end() );
               if( import_key( account_name, it->second ) )
               {
                  // somebody else beat our pending registration, there is
                  //    nothing we can do except log it and move on
                  ilog( "account ${name} registered by someone else first!",
                        ("name", account_name) );
                  // might as well remove it from pending regs,
                  //    because there is now no way this registration
                  //    can become valid (even in the extremely rare
                  //    possibility of migrating to a fork where the
                  //    name is available, the user can always
                  //    manually re-register)
               }
               _wallet.pending_account_registrations.erase( it );
            }
         }

         return;
      }

      wallet_data             _wallet;
      fc::api<login_api>      _remote_api;
      fc::api<database_api>   _remote_db;
      fc::api<network_api>    _remote_net;
};

FC_API( wallet_api,
        (help)
        (import_key)
        (suggest_brain_key)
        (create_account_with_brain_key)
        (transfer)
        (get_account)
        (get_object)
        (normalize_brain_key)
       )

struct help_visitor
{
   help_visitor( std::stringstream& s ):ss(s){}
   std::stringstream& ss;
   template<typename R, typename... Args>
   void operator()( const char* name, std::function<R(Args...)>& memb )const {
      ss << std::setw(40) << std::left << fc::get_typename<R>::name() << " " << name << "( ";
      vector<string> args{ fc::get_typename<Args>::name()... };
      for( uint32_t i = 0; i < args.size(); ++i )
         ss << args[i] << (i==args.size()-1?" ":", ");
      ss << ")\n";
   }

};
string  wallet_api::help()const
{
   fc::api<wallet_api> tmp;
   std::stringstream ss;
   tmp->visit( help_visitor(ss) );
   return ss.str();
}

int main( int argc, char** argv )
{
   try {
      FC_ASSERT( argc > 1, "usage: ${cmd} WALLET_FILE", ("cmd",argv[0]) );

      fc::ecc::private_key genesis_private_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("genesis")));
      idump( (key_to_wif( genesis_private_key ) ) );
      idump( (account_id_type()) );

      wallet_data wallet;
      fc::path wallet_file(argv[1]);
      if( fc::exists( wallet_file ) )
          wallet = fc::json::from_file( wallet_file ).as<wallet_data>();

      fc::http::websocket_client client;
      auto con  = client.connect( wallet.ws_server );
      auto apic = std::make_shared<fc::rpc::websocket_api_connection>(*con);
      con->closed.connect( [&](){ elog( "connection closed" ); } );

      auto remote_api = apic->get_remote_api< login_api >();
      FC_ASSERT( remote_api->login( wallet.ws_user, wallet.ws_password ) );

      auto wapiptr = std::make_shared<wallet_api>(remote_api);
      wapiptr->_wallet = wallet;

      fc::api<wallet_api> wapi(wapiptr);

      auto wallet_cli = std::make_shared<fc::rpc::cli>();
      wallet_cli->format_result( "help", [&]( variant result, const fc::variants& a) {
                                    return result.get_string();
                                });
      wallet_cli->register_api( wapi );
      wallet_cli->start();
      wallet_cli->wait();
   }
   catch ( const fc::exception& e )
   {
      std::cout << e.to_detail_string() << "\n";
   }
   return -1;
}
<|endoftext|>


<commit_before>#include "runner/at_handler.hh"

#include <iostream>
#include <list>

#include "scheduler/tag.hh"

namespace runner
{

  class AtJob
  {
  public:
    AtJob(rObject condition, rObject clause, rObject on_leave,
	  scheduler::tags_type tags);
    bool blocked() const;
    bool frozen() const;
    const rObject& condition_get() const;
    const rObject& clause_get() const;
    const rObject& on_leave_get() const;
    bool triggered_get() const;
    void triggered_set(bool);
    const scheduler::tags_type& tags_get() const;
  private:
    rObject condition_;
    rObject clause_;
    rObject on_leave_;
    bool triggered_;
    scheduler::tags_type tags_;
  };

  class AtHandler : public Runner
  {
  public:
    AtHandler(const Runner&);
    virtual ~AtHandler();
    virtual void work();
    virtual bool frozen() const;
    virtual bool blocked() const;
    void add_job(AtJob*);
  private:
    void complete_tags(const AtJob&);
    void rebuild_tags();
    typedef std::vector<AtJob*> at_jobs_type;
    at_jobs_type jobs_;
    bool yielding;
    scheduler::tags_type tags_;
  };

  // There is only one at job handler. It will be created if it doesn't exist
  // and destroyed when it has no more jobs to handle.
  static AtHandler* at_job_handler;

  AtHandler::AtHandler(const Runner& model)
    : Runner(model, 0),
      yielding(false)
  {
  }

  AtHandler::~AtHandler()
  {
  }

  void
  AtHandler::work()
  {
    bool check_for_blocked = true;
    bool tags_need_rebuilding;
    side_effect_free_set(true);

    while (true)
    {
      non_interruptible_set(true);
      yielding = false;
      tags_need_rebuilding = false;

      // We have been woken up, either because we may have something to do
      // or because some tag conditions have changed.

      at_jobs_type pending;
      pending.reserve(jobs_.size());

      // If we have to check for blocked jobs, do it at the beginning
      // to make sure we do not miss a "stop" because some condition
      // evaluation mistakenly reenters the scheduler. So instead of
      // just swapping pending_ and jobs, we will build pending using
      // the unblocked jobs.

      if (check_for_blocked)
      {
	foreach(AtJob* job, jobs_)
	  if (job->blocked())
	  {
	    tags_need_rebuilding = true;
	    delete job;
	  }
	  else
	    pending.push_back(job);
      }
      else // Use all jobs, none has been blocked
	swap(jobs_, pending);

      foreach (AtJob* job, pending)
      {
	// If job has been frozen, we will not consider it for the moment.
	if (job->frozen())
	{
	  jobs_.push_back(job);
	  continue;
	}

	// Check the job condition and continue if it has not changed.
	bool new_state;
	try
	{
	  new_state =
	    object::is_true(urbi_call(*this, job->condition_get(), SYMBOL(eval)));
	}
	catch (const kernel::exception& ke)
	{
	  std::cerr << "at condition triggered an exception: " << ke.what()
		    << std::endl;
	  tags_need_rebuilding = true;
	  delete job;
	  continue;
	}
	catch (...)
	{
	  std::cerr << "at condition triggered an exception\n";
	  delete job;
	  continue;
	}
	if (new_state == job->triggered_get())
	{
	  jobs_.push_back(job);
	  continue;
	}

	// There has been a change in the condition, act accordingly depending
	// on whether we have seen a rising or a falling edge and save the
	// condition evaluation result.
	const rObject& to_launch =
	  new_state ? job->clause_get() : job->on_leave_get();
	if (to_launch != object::nil_class)
	{
	  // Temporarily install the needed tags as the current tags.
	  tags_set(job->tags_get());

	  // We do not need to check for an exception here as "detach",
	  // which is the function being called, will not throw and any
	  // exception thrown in the detached runner will not be caught
	  // here anyway.
	  urbi_call(*this, to_launch, SYMBOL(eval));
	}
	job->triggered_set(new_state);
	jobs_.push_back(job);
      }

      // If we have no more jobs, we can destroy ourselves.
      if (jobs_.empty())
      {
	at_job_handler = 0;
	terminate_now();
      }

      non_interruptible_set(false);
      check_for_blocked = false;
      yielding = true;

      // Rebuild tags if our list of jobs has changed.
      if (tags_need_rebuilding)
	rebuild_tags();

      // Go to sleep
      try
      {
	// We want to appear blocked only when explicitly yielding and
	// catching the exception. If, by mistake, a condition evaluation
	// yields and is blocked, we do not want it to get the bogus
        // exception.
	yield_until_things_changed();
      }
      catch (const scheduler::BlockedException& e)
      {
	// We have at least one "at" job which needs to be blocked.
	check_for_blocked = true;
      }
      catch (const kernel::exception& e)
      {
	std::cerr << "at job handler exited with exception " << e.what()
		  << std::endl;
	throw;
      }
      catch (...)
      {
	std::cerr << "at job handler exited with unknown exception\n";
	throw;
      }
    }
  }

  bool
  AtHandler::frozen() const
  {
    return false;
  }

  bool
  AtHandler::blocked() const
  {
    if (!yielding)
      return false;
    foreach (const scheduler::rTag& t, tags_)
      if (t->blocked())
	return true;
    return false;
  }

  void
  AtHandler::add_job(AtJob* job)
  {
    jobs_.push_back(job);
    complete_tags(*job);
  }

  void
  AtHandler::rebuild_tags()
  {
    tags_.clear();
    foreach (const AtJob* job, jobs_)
      complete_tags(*job);
  }

  void
  AtHandler::complete_tags(const AtJob& job)
  {
    foreach (scheduler::rTag t, job.tags_get())
    {
      foreach (const scheduler::rTag& u, tags_)
	if (t == u)
	  goto already_found;
      tags_.push_back(t);
    already_found:
      ;
    }
  }

  AtJob::AtJob(rObject condition, rObject clause, rObject on_leave,
	       scheduler::tags_type tags)
    : condition_(condition),
      clause_(clause),
      on_leave_(on_leave),
      triggered_(false),
      tags_(tags)
  {
  }

  bool
  AtJob::blocked() const
  {
    foreach(const scheduler::rTag& tag, tags_)
      if (tag->blocked())
	return true;
    return false;
  }

  bool
  AtJob::frozen() const
  {
    foreach(const scheduler::rTag& tag, tags_)
      if (tag->frozen())
	return true;
    return false;
  }

  const rObject&
  AtJob::condition_get() const
  {
    return condition_;
  }

  const rObject&
  AtJob::clause_get() const
  {
    return clause_;
  }

  const rObject&
  AtJob::on_leave_get() const
  {
    return on_leave_;
  }

  bool
  AtJob::triggered_get() const
  {
    return triggered_;
  }

  void
  AtJob::triggered_set(bool t)
  {
    triggered_ = t;
  }

  const scheduler::tags_type&
  AtJob::tags_get() const
  {
    return tags_;
  }

  void
  register_at_job(const runner::Runner& starter,
		  rObject condition,
		  rObject clause,
		  rObject on_leave)
  {
    if (!at_job_handler)
    {
      at_job_handler = new AtHandler(starter);
      at_job_handler->start_job();
    }
    AtJob* job = new AtJob(condition,
			   clause,
			   on_leave,
			   starter.tags_get());
    at_job_handler->add_job(job);
  }

} // namespace runner
<commit_msg>Use pointer containers in at job handler.<commit_after>#include "runner/at_handler.hh"

#include <iostream>
#include <list>

#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>

#include "scheduler/tag.hh"

namespace runner
{

  class AtJob
  {
  public:
    AtJob(rObject condition, rObject clause, rObject on_leave,
	  scheduler::tags_type tags);
    bool blocked() const;
    bool frozen() const;
    const rObject& condition_get() const;
    const rObject& clause_get() const;
    const rObject& on_leave_get() const;
    bool triggered_get() const;
    void triggered_set(bool);
    const scheduler::tags_type& tags_get() const;
  private:
    rObject condition_;
    rObject clause_;
    rObject on_leave_;
    bool triggered_;
    scheduler::tags_type tags_;
  };

  class AtHandler : public Runner
  {
  public:
    AtHandler(const Runner&);
    virtual ~AtHandler();
    virtual void work();
    virtual bool frozen() const;
    virtual bool blocked() const;
    void add_job(AtJob*);
  private:
    void complete_tags(const AtJob&);
    void rebuild_tags();
    typedef boost::ptr_vector<AtJob> at_jobs_type;
    at_jobs_type jobs_;
    bool yielding;
    scheduler::tags_type tags_;
  };

  // There is only one at job handler. It will be created if it doesn't exist
  // and destroyed when it has no more jobs to handle.
  static AtHandler* at_job_handler;

  AtHandler::AtHandler(const Runner& model)
    : Runner(model, 0),
      yielding(false)
  {
  }

  AtHandler::~AtHandler()
  {
    jobs_.release();
  }

  void
  AtHandler::work()
  {
    bool check_for_blocked = true;
    bool tags_need_rebuilding = false;
    side_effect_free_set(true);

    while (true)
    {
      non_interruptible_set(true);
      yielding = false;

      // If we have to check for blocked jobs, do it at the beginning
      // to make sure we do not miss a "stop" because some condition
      // evaluation mistakenly reenters the scheduler. We know that we
      // have to check for blocked jobs because we have had an indication
      // that tags needed to be rebuilt.

      if (tags_need_rebuilding)
	jobs_.erase_if(boost::bind(&AtJob::blocked, _1));

      for (at_jobs_type::iterator job = jobs_.begin();
	   job != jobs_.end();
	   /* Do not increment as we will also use erase() to advance */)
      {
	// If job has been frozen, we will not consider it for the moment.
	if (job->frozen())
	{
	  ++job;
	  continue;
	}

	// Check the job condition and continue if it has not changed.
	bool new_state;
	try
	{
	  new_state =
	    object::is_true(urbi_call(*this, job->condition_get(), SYMBOL(eval)));
	}
	catch (const kernel::exception& ke)
	{
	  std::cerr << "at condition triggered an exception: " << ke.what()
		    << std::endl;
	  tags_need_rebuilding = true;
	  job = jobs_.erase(job);
	  continue;
	}
	catch (...)
	{
	  std::cerr << "at condition triggered an exception\n";
	  job = jobs_.erase(job);
	  continue;
	}
	if (new_state == job->triggered_get())
	{
	  ++job;
	  continue;
	}

	// There has been a change in the condition, act accordingly depending
	// on whether we have seen a rising or a falling edge and save the
	// condition evaluation result.
	const rObject& to_launch =
	  new_state ? job->clause_get() : job->on_leave_get();
	if (to_launch != object::nil_class)
	{
	  // Temporarily install the needed tags as the current tags.
	  tags_set(job->tags_get());

	  // We do not need to check for an exception here as "detach",
	  // which is the function being called, will not throw and any
	  // exception thrown in the detached runner will not be caught
	  // here anyway.
	  urbi_call(*this, to_launch, SYMBOL(eval));
	}
	job->triggered_set(new_state);
	++job;
      }

      // If we have no more jobs, we can destroy ourselves.
      if (jobs_.empty())
      {
	at_job_handler = 0;
	terminate_now();
      }

      non_interruptible_set(false);
      check_for_blocked = false;
      yielding = true;

      // Rebuild tags if our list of jobs has changed.
      if (tags_need_rebuilding)
	rebuild_tags();
      tags_need_rebuilding = false;

      // Go to sleep
      try
      {
	// We want to appear blocked only when explicitly yielding and
	// catching the exception. If, by mistake, a condition evaluation
	// yields and is blocked, we do not want it to get the bogus
        // exception.
	yield_until_things_changed();
      }
      catch (const scheduler::BlockedException& e)
      {
	// We have at least one "at" job which needs to be blocked.
	tags_need_rebuilding = true;
      }
      catch (const kernel::exception& e)
      {
	std::cerr << "at job handler exited with exception " << e.what()
		  << std::endl;
	throw;
      }
      catch (...)
      {
	std::cerr << "at job handler exited with unknown exception\n";
	throw;
      }
    }
  }

  bool
  AtHandler::frozen() const
  {
    return false;
  }

  bool
  AtHandler::blocked() const
  {
    if (!yielding)
      return false;
    foreach (const scheduler::rTag& t, tags_)
      if (t->blocked())
	return true;
    return false;
  }

  void
  AtHandler::add_job(AtJob* job)
  {
    jobs_.push_back(job);
    complete_tags(*job);
  }

  void
  AtHandler::rebuild_tags()
  {
    tags_.clear();
    foreach (const AtJob& job, jobs_)
      complete_tags(job);
  }

  void
  AtHandler::complete_tags(const AtJob& job)
  {
    foreach (scheduler::rTag t, job.tags_get())
    {
      foreach (const scheduler::rTag& u, tags_)
	if (t == u)
	  goto already_found;
      tags_.push_back(t);
    already_found:
      ;
    }
  }

  AtJob::AtJob(rObject condition, rObject clause, rObject on_leave,
	       scheduler::tags_type tags)
    : condition_(condition),
      clause_(clause),
      on_leave_(on_leave),
      triggered_(false),
      tags_(tags)
  {
  }

  bool
  AtJob::blocked() const
  {
    foreach(const scheduler::rTag& tag, tags_)
      if (tag->blocked())
	return true;
    return false;
  }

  bool
  AtJob::frozen() const
  {
    foreach(const scheduler::rTag& tag, tags_)
      if (tag->frozen())
	return true;
    return false;
  }

  const rObject&
  AtJob::condition_get() const
  {
    return condition_;
  }

  const rObject&
  AtJob::clause_get() const
  {
    return clause_;
  }

  const rObject&
  AtJob::on_leave_get() const
  {
    return on_leave_;
  }

  bool
  AtJob::triggered_get() const
  {
    return triggered_;
  }

  void
  AtJob::triggered_set(bool t)
  {
    triggered_ = t;
  }

  const scheduler::tags_type&
  AtJob::tags_get() const
  {
    return tags_;
  }

  void
  register_at_job(const runner::Runner& starter,
		  rObject condition,
		  rObject clause,
		  rObject on_leave)
  {
    if (!at_job_handler)
    {
      at_job_handler = new AtHandler(starter);
      at_job_handler->start_job();
    }
    AtJob* job = new AtJob(condition,
			   clause,
			   on_leave,
			   starter.tags_get());
    at_job_handler->add_job(job);
  }

} // namespace runner
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2013 Evgeniy Andreev (gsomix)
 */

#include <cstdio>_
#include <shogun/io/LineReader.h>

using namespace shogun;

CLineReader::CLineReader()
	: m_stream(NULL), m_max_line_length(0), m_next_line_length(-1)
{
	m_buffer=new CCircularBuffer(0);
}

CLineReader::CLineReader(FILE* stream, char delimiter)
	: m_stream(stream), m_max_line_length(10*1024*1024), m_next_line_length(-1)
{
	m_buffer=new CCircularBuffer(m_max_line_length);
	m_tokenizer=new CDelimiterTokenizer();
	m_tokenizer->delimiters[delimiter]=1;
	m_buffer->set_tokenizer(m_tokenizer);
}

CLineReader::CLineReader(int32_t max_line_length, FILE* stream, char delimiter)
	: m_stream(stream), m_max_line_length(max_line_length), m_next_line_length(-1)
{
	m_buffer=new CCircularBuffer(m_max_line_length);
	m_tokenizer=new CDelimiterTokenizer();
	m_tokenizer->delimiters[delimiter]=1;
	m_buffer->set_tokenizer(m_tokenizer);
}

CLineReader::~CLineReader()
{
	SG_UNREF(m_tokenizer);
	SG_UNREF(m_buffer);
}

bool CLineReader::has_next_line()
{
	if (m_stream==NULL || m_max_line_length==0)
	{
		SG_ERROR("Class is not initialized");
		return false;
	}

	if (ferror(m_stream))
	{
		SG_ERROR("Error reading file");
		return false;
	}

	if (feof(m_stream) && m_buffer->num_bytes_contained()<=0)
		return false; // nothing to read

	return true;
}

SGVector<char> CLineReader::get_next_line()
{
	SGVector<char> line;

	m_next_line_length=read_line();
	if (m_next_line_length==-1)
		line=SGVector<char>();
	else
		line=copy_line(m_next_line_length);

	return line;
}

void CLineReader::set_delimiter(char delimiter)
{
	m_tokenizer->delimiters[delimiter]=1;
}

void CLineReader::clear_delimiters()
{
	m_tokenizer->clear_delimiters();
}

int32_t CLineReader::read_line()
{
	int32_t line_end=0;
	int32_t bytes_to_skip=0;
	int32_t bytes_to_read=0;

	while (1)
	{
		line_end+=m_buffer->next_token_idx(bytes_to_skip)-bytes_to_skip;

		if (m_buffer->num_bytes_contained()!=0 && line_end<m_buffer->num_bytes_contained())
			return line_end;
		else if (m_buffer->available()==0)
			return -1; // we need some limit in case file does not contain delimiter

		// if there is no delimiter in buffer
		// try get more data from stream
		// and write it into buffer
		if (m_buffer->available() < m_max_line_length)
			bytes_to_read=m_buffer->available();
		else
			bytes_to_read=m_max_line_length;

		if (feof(m_stream))
			return line_end;
		else
			m_buffer->push(m_stream, bytes_to_read);

		if (ferror(m_stream))
		{
			SG_ERROR("Error reading file");
			return -1;
		}
	}
}

SGVector<char> CLineReader::copy_line(int32_t line_len)
{
	SGVector<char> line;

	if (line_len==0)
		line=SGVector<char>();
	else
		line=m_buffer->pop(line_len);

	m_buffer->skip_characters(1);

	return line;
}
<commit_msg>Remove extra tokens at end of #include<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2013 Evgeniy Andreev (gsomix)
 */

#include <cstdio>
#include <shogun/io/LineReader.h>

using namespace shogun;

CLineReader::CLineReader()
	: m_stream(NULL), m_max_line_length(0), m_next_line_length(-1)
{
	m_buffer=new CCircularBuffer(0);
}

CLineReader::CLineReader(FILE* stream, char delimiter)
	: m_stream(stream), m_max_line_length(10*1024*1024), m_next_line_length(-1)
{
	m_buffer=new CCircularBuffer(m_max_line_length);
	m_tokenizer=new CDelimiterTokenizer();
	m_tokenizer->delimiters[delimiter]=1;
	m_buffer->set_tokenizer(m_tokenizer);
}

CLineReader::CLineReader(int32_t max_line_length, FILE* stream, char delimiter)
	: m_stream(stream), m_max_line_length(max_line_length), m_next_line_length(-1)
{
	m_buffer=new CCircularBuffer(m_max_line_length);
	m_tokenizer=new CDelimiterTokenizer();
	m_tokenizer->delimiters[delimiter]=1;
	m_buffer->set_tokenizer(m_tokenizer);
}

CLineReader::~CLineReader()
{
	SG_UNREF(m_tokenizer);
	SG_UNREF(m_buffer);
}

bool CLineReader::has_next_line()
{
	if (m_stream==NULL || m_max_line_length==0)
	{
		SG_ERROR("Class is not initialized");
		return false;
	}

	if (ferror(m_stream))
	{
		SG_ERROR("Error reading file");
		return false;
	}

	if (feof(m_stream) && m_buffer->num_bytes_contained()<=0)
		return false; // nothing to read

	return true;
}

SGVector<char> CLineReader::get_next_line()
{
	SGVector<char> line;

	m_next_line_length=read_line();
	if (m_next_line_length==-1)
		line=SGVector<char>();
	else
		line=copy_line(m_next_line_length);

	return line;
}

void CLineReader::set_delimiter(char delimiter)
{
	m_tokenizer->delimiters[delimiter]=1;
}

void CLineReader::clear_delimiters()
{
	m_tokenizer->clear_delimiters();
}

int32_t CLineReader::read_line()
{
	int32_t line_end=0;
	int32_t bytes_to_skip=0;
	int32_t bytes_to_read=0;

	while (1)
	{
		line_end+=m_buffer->next_token_idx(bytes_to_skip)-bytes_to_skip;

		if (m_buffer->num_bytes_contained()!=0 && line_end<m_buffer->num_bytes_contained())
			return line_end;
		else if (m_buffer->available()==0)
			return -1; // we need some limit in case file does not contain delimiter

		// if there is no delimiter in buffer
		// try get more data from stream
		// and write it into buffer
		if (m_buffer->available() < m_max_line_length)
			bytes_to_read=m_buffer->available();
		else
			bytes_to_read=m_max_line_length;

		if (feof(m_stream))
			return line_end;
		else
			m_buffer->push(m_stream, bytes_to_read);

		if (ferror(m_stream))
		{
			SG_ERROR("Error reading file");
			return -1;
		}
	}
}

SGVector<char> CLineReader::copy_line(int32_t line_len)
{
	SGVector<char> line;

	if (line_len==0)
		line=SGVector<char>();
	else
		line=m_buffer->pop(line_len);

	m_buffer->skip_characters(1);

	return line;
}
<|endoftext|>