<commit_before>//
// Copyright (c) 2012, University of Erlangen-Nuremberg
// Copyright (c) 2012, Siemens AG
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

#include "hipacc.hpp"

#include <iostream>
#include <hipacc_helper.hpp>

#define WIDTH  4032
#define HEIGHT 3024
#define IMAGE  "../../common/img/fuerte_ship.jpg"

using namespace hipacc;
using namespace hipacc::math;

// Kernel description in Hipacc
class ColorConversion : public Kernel<uchar> {
    private:
        Accessor<uchar4> ∈

    public:
        ColorConversion(IterationSpace<uchar> &iter, Accessor<uchar4> &acc)
              : Kernel(iter), in(acc) {
            add_accessor(&in);
        }

        void kernel() {
            uchar4 pixel = in();
            output() = .3f*pixel.x + .59f*pixel.y + .11f*pixel.z + .5f;
        }
};

// forward declaration of reference implementation
void color_conversion(uchar4 *in, uchar *out, int width, int height);

/*************************************************************************
 * Main function                                                         *
 *************************************************************************/
int main(int argc, const char **argv) {
    const int width = WIDTH;
    const int height = HEIGHT;
    float timing = 0;

    // host memory for image of width x height pixels
    uchar4 *input = (uchar4*)load_data<uchar>(width, height, 4, IMAGE);
    uchar *ref_out = new uchar[width*height];

    std::cout << "Calculating Hipacc color conversion ..." << std::endl;

    //************************************************************************//

    // input and output image of width x height pixels
    Image<uchar4> in(width, height, input);
    Image<uchar> out(width, height);

    Accessor<uchar4> acc(in);

    IterationSpace<uchar> iter(out);
    ColorConversion filter(iter, acc);

    filter.execute();
    timing = hipacc_last_kernel_timing();

    // get pointer to result data
    uchar *output = out.data();

    //************************************************************************//

    std::cout << "Hipacc: " << timing << " ms, "
              << (width*height/timing)/1000 << " Mpixel/s" << std::endl;

    std::cout << "Calculating reference ..." << std::endl;
    double start = time_ms();
    color_conversion(input, ref_out, width, height);
    double end = time_ms();
    std::cout << "Reference: " << end-start << " ms, "
              << (width*height/(end-start))/1000 << " Mpixel/s" << std::endl;

    compare_results(output, ref_out, width, height);

    save_data(width, height, 4, input, "input.jpg");
    save_data(width, height, 1, output, "output.jpg");
    show_data(width, height, 1, output, "output.jpg");

    // free memory
    delete[] input;
    delete[] ref_out;

    return EXIT_SUCCESS;
}

// color conversion reference
void color_conversion(uchar4 *in, uchar *out, int width, int height) {
    for (int p = 0; p < width*height; ++p) {
        uchar4 pixel = in[p];
        out[p] = .3f*pixel.x + .59f*pixel.y + .11f*pixel.z + .5f;
    }
}
<commit_msg>Fixed visuals for color conversion sample<commit_after>//
// Copyright (c) 2012, University of Erlangen-Nuremberg
// Copyright (c) 2012, Siemens AG
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

#include "hipacc.hpp"

#include <iostream>
#include <hipacc_helper.hpp>

#define WIDTH  4032
#define HEIGHT 3024
#define IMAGE  "../../common/img/fuerte_ship.jpg"

using namespace hipacc;
using namespace hipacc::math;

// Kernel description in Hipacc
class ColorConversion : public Kernel<uchar> {
    private:
        Accessor<uchar4> ∈

    public:
        ColorConversion(IterationSpace<uchar> &iter, Accessor<uchar4> &acc)
              : Kernel(iter), in(acc) {
            add_accessor(&in);
        }

        void kernel() {
            uchar4 pixel = in();
            output() = .3f*pixel.x + .59f*pixel.y + .11f*pixel.z + .5f;
        }
};

// forward declaration of reference implementation
void color_conversion(uchar4 *in, uchar *out, int width, int height);

/*************************************************************************
 * Main function                                                         *
 *************************************************************************/
int main(int argc, const char **argv) {
    const int width = WIDTH;
    const int height = HEIGHT;
    float timing = 0;

    // host memory for image of width x height pixels
    uchar4 *input = (uchar4*)load_data<uchar>(width, height, 4, IMAGE);
    uchar *ref_out = new uchar[width*height];

    std::cout << "Calculating Hipacc color conversion ..." << std::endl;

    //************************************************************************//

    // input and output image of width x height pixels
    Image<uchar4> in(width, height, input);
    Image<uchar> out(width, height);

    Accessor<uchar4> acc(in);

    IterationSpace<uchar> iter(out);
    ColorConversion filter(iter, acc);

    filter.execute();
    timing = hipacc_last_kernel_timing();

    // get pointer to result data
    uchar *output = out.data();

    //************************************************************************//

    std::cout << "Hipacc: " << timing << " ms, "
              << (width*height/timing)/1000 << " Mpixel/s" << std::endl;

    std::cout << "Calculating reference ..." << std::endl;
    double start = time_ms();
    color_conversion(input, ref_out, width, height);
    double end = time_ms();
    std::cout << "Reference: " << end-start << " ms, "
              << (width*height/(end-start))/1000 << " Mpixel/s" << std::endl;

    compare_results(output, ref_out, width, height);

    save_data(width, height, 4, (uchar*)input, "input.jpg");
    save_data(width, height, 1, output, "output.jpg");
    show_data(width, height, 1, output, "output.jpg");

    // free memory
    delete[] input;
    delete[] ref_out;

    return EXIT_SUCCESS;
}

// color conversion reference
void color_conversion(uchar4 *in, uchar *out, int width, int height) {
    for (int p = 0; p < width*height; ++p) {
        uchar4 pixel = in[p];
        out[p] = .3f*pixel.x + .59f*pixel.y + .11f*pixel.z + .5f;
    }
}
<|endoftext|>


<commit_before>/**
 * @file HoughCircle_Demo.cpp
 * @brief Demo code for Hough Transform
 * @author OpenCV team
 */

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;

namespace
{
    // windows and trackbars name
    const std::string windowName = "Hough Circle Detection Demo";
    const std::string cannyThresholdTrackbarName = "Canny threshold";
    const std::string accumulatorThresholdTrackbarName = "Accumulator Threshold";

    // initial and max values of the parameters of interests.
    const int cannyThresholdInitialValue = 200;
    const int accumulatorThresholdInitialValue = 50;
    const int maxAccumulatorThreshold = 200;
    const int maxCannyThreshold = 255;

    void HoughDetection(const Mat& src_gray, const Mat& src_display, int cannyThreshold, int accumulatorThreshold)
    {
       // will hold the results of the detection
       std::vector<Vec3f> circles;
       // runs the actual detection
       HoughCircles( src_gray, circles, HOUGH_GRADIENT, 1, src_gray.rows/8, cannyThreshold, accumulatorThreshold, 0, 0 );

       // clone the colour, input image for displaying purposes
       Mat display = src_display.clone();
       for( size_t i = 0; i < circles.size(); i++ )
       {
            Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
            int radius = cvRound(circles[i][2]);
            // circle center
            circle( display, center, 3, Scalar(0,255,0), -1, 8, 0 );
            // circle outline
            circle( display, center, radius, Scalar(0,0,255), 3, 8, 0 );
       }

       // shows the results
       imshow( windowName, display);
    }
}

int main(int, char** argv)
{
   Mat src, src_gray;

    // Read the image
    src = imread( argv[1], 1 );

   if( !src.data )
     { return -1; }

    // Convert it to gray
    cvtColor( src, src_gray, COLOR_BGR2GRAY );

    // Reduce the noise so we avoid false circle detection
    GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );

    //declare and initialize both parameters that are subjects to change
    int cannyThreshold = cannyThresholdInitialValue;
    int accumulatorThreshold = accumulatorThresholdInitialValue;

    // create the main window, and attach the trackbars
    namedWindow( windowName, WINDOW_AUTOSIZE );
    createTrackbar(cannyThresholdTrackbarName, windowName, &cannyThreshold,maxCannyThreshold);
    createTrackbar(accumulatorThresholdTrackbarName, windowName, &accumulatorThreshold, maxAccumulatorThreshold);

    // inifinite loop to display
    // and refresh the content of the output image
    // unti the user presses q or Q
    int key = 0;
    while(key != 'q' && key != 'Q')
    {
        // those paramaters cannot be =0
        // so we must check here
        cannyThreshold = std::max(cannyThreshold, 1);
        accumulatorThreshold = std::max(accumulatorThreshold, 1);

        //runs the detection, and update the display
        HoughDetection(src_gray, src, cannyThreshold, accumulatorThreshold);

        // get user key
        key = waitKey(10);
    }

    return 0;
}
<commit_msg>improved error handling<commit_after>/**
 * @file HoughCircle_Demo.cpp
 * @brief Demo code for Hough Transform
 * @author OpenCV team
 */

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>

using namespace cv;

namespace
{
    // windows and trackbars name
    const std::string windowName = "Hough Circle Detection Demo";
    const std::string cannyThresholdTrackbarName = "Canny threshold";
    const std::string accumulatorThresholdTrackbarName = "Accumulator Threshold";

    // initial and max values of the parameters of interests.
    const int cannyThresholdInitialValue = 200;
    const int accumulatorThresholdInitialValue = 50;
    const int maxAccumulatorThreshold = 200;
    const int maxCannyThreshold = 255;

    void HoughDetection(const Mat& src_gray, const Mat& src_display, int cannyThreshold, int accumulatorThreshold)
    {
       // will hold the results of the detection
       std::vector<Vec3f> circles;
       // runs the actual detection
       HoughCircles( src_gray, circles, HOUGH_GRADIENT, 1, src_gray.rows/8, cannyThreshold, accumulatorThreshold, 0, 0 );

       // clone the colour, input image for displaying purposes
       Mat display = src_display.clone();
       for( size_t i = 0; i < circles.size(); i++ )
       {
            Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
            int radius = cvRound(circles[i][2]);
            // circle center
            circle( display, center, 3, Scalar(0,255,0), -1, 8, 0 );
            // circle outline
            circle( display, center, radius, Scalar(0,0,255), 3, 8, 0 );
       }

       // shows the results
       imshow( windowName, display);
    }
}

int main(int, char** argv)
{
   Mat src, src_gray;

    // Read the image
    src = imread( argv[1], 1 );

   if( !src.data )
   {
       std::cerr<<"Invalid input image\n";
       std::cout<<"Usage : tutorial_HoughCircle_Demo <path_to_input_image>\n";
       return -1;
   }

    // Convert it to gray
    cvtColor( src, src_gray, COLOR_BGR2GRAY );

    // Reduce the noise so we avoid false circle detection
    GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );

    //declare and initialize both parameters that are subjects to change
    int cannyThreshold = cannyThresholdInitialValue;
    int accumulatorThreshold = accumulatorThresholdInitialValue;

    // create the main window, and attach the trackbars
    namedWindow( windowName, WINDOW_AUTOSIZE );
    createTrackbar(cannyThresholdTrackbarName, windowName, &cannyThreshold,maxCannyThreshold);
    createTrackbar(accumulatorThresholdTrackbarName, windowName, &accumulatorThreshold, maxAccumulatorThreshold);

    // inifinite loop to display
    // and refresh the content of the output image
    // unti the user presses q or Q
    int key = 0;
    while(key != 'q' && key != 'Q')
    {
        // those paramaters cannot be =0
        // so we must check here
        cannyThreshold = std::max(cannyThreshold, 1);
        accumulatorThreshold = std::max(accumulatorThreshold, 1);

        //runs the detection, and update the display
        HoughDetection(src_gray, src, cannyThreshold, accumulatorThreshold);

        // get user key
        key = waitKey(10);
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "ghost/config.h"
#include "ghost/types.h"
#include "ghost/densemat.h"
#include "ghost/util.h"
#include "ghost/math.h"
#include "ghost/tsmm.h"
#include "ghost/tsmm_gen.h"
#include "ghost/tsmm_avx_gen.h"
#include "ghost/tsmm_sse_gen.h"

#include <map>

using namespace std;

static bool operator<(const ghost_tsmm_parameters_t &a, const ghost_tsmm_parameters_t &b)
{
    return ghost_hash(a.dt,a.xcols,ghost_hash(a.vcols,a.impl,0)) < ghost_hash(b.dt,b.xcols,ghost_hash(b.vcols,b.impl,0));
}

static map<ghost_tsmm_parameters_t, ghost_tsmm_kernel_t> ghost_tsmm_kernels;

ghost_error_t ghost_tsmm_valid(ghost_densemat_t *x, ghost_densemat_t *v,  const char * transv,
ghost_densemat_t *w, const char *transw, void *alpha, void *beta, int reduce, int printerror)
{
    if (x->traits.datatype != v->traits.datatype || x->traits.datatype != w->traits.datatype) {
        if (printerror) {
            ERROR_LOG("Different data types!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (x == v) {
        if (printerror) {
           ERROR_LOG("x must not be equal to v!");
        }
        return GHOST_ERR_INVALID_ARG;
    }

    if (w->traits.storage != GHOST_DENSEMAT_COLMAJOR) {
        if (printerror) {
           ERROR_LOG("w must be stored col-major!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (x->traits.storage != GHOST_DENSEMAT_ROWMAJOR) {
        if (printerror) {
            ERROR_LOG("x must be stored row-major!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (v->traits.storage != GHOST_DENSEMAT_ROWMAJOR) {
        if (printerror) {
           ERROR_LOG("v must be stored row-major!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if ((x->traits.flags & GHOST_DENSEMAT_SCATTERED) || (v->traits.flags & GHOST_DENSEMAT_SCATTERED) || (w->traits.flags & GHOST_DENSEMAT_SCATTERED)) {
        if (printerror) {
            ERROR_LOG("Scattered views not supported!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (reduce != GHOST_GEMM_NO_REDUCE) {
        if (printerror) {
            ERROR_LOG("Only NO_REDUCE valid!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (strncasecmp(transv,"N",1)) {
        if (printerror) {
            ERROR_LOG("v must not be transposed!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (strncasecmp(transw,"N",1)) {
        if (printerror) {
            ERROR_LOG("w must not be transposed!");
        }
        return GHOST_ERR_INVALID_ARG;
    }

    UNUSED(alpha);
    UNUSED(beta);

    return GHOST_SUCCESS;
}

ghost_error_t ghost_tsmm(ghost_densemat_t *x, ghost_densemat_t *v, ghost_densemat_t *w, void *alpha, void *beta)
{
    GHOST_FUNC_ENTER(GHOST_FUNCTYPE_MATH);
    ghost_error_t ret;

    if ((ret = ghost_tsmm_valid(x,v,"N",w,"N",alpha,beta,GHOST_GEMM_NO_REDUCE,1)) != GHOST_SUCCESS) {
        return ret;
    }

    if (ghost_tsmm_kernels.empty()) {
#include "tsmm.def"
#include "tsmm_avx.def"
#include "tsmm_sse.def"
    }

    ghost_tsmm_parameters_t p;
    ghost_tsmm_kernel_t kernel = NULL;
#ifdef GHOST_HAVE_MIC
    p.impl = GHOST_IMPLEMENTATION_MIC;
#elif defined(GHOST_HAVE_AVX)
    p.impl = GHOST_IMPLEMENTATION_AVX;
#elif defined(GHOST_HAVE_SSE)
    p.impl = GHOST_IMPLEMENTATION_SSE;
#else
    p.impl = GHOST_IMPLEMENTATION_PLAIN;
#endif

    p.alignment = GHOST_ALIGNED;
    p.dt = x->traits.datatype;

    p.xcols = x->traits.ncols;
    p.vcols = v->traits.ncols;
    if (p.xcols == 2) {
#ifdef GHOST_HAVE_SSE
        PERFWARNING_LOG("Use SSE for ncols==2");
        p.impl = GHOST_IMPLEMENTATION_SSE;
#endif
    }
    if (p.xcols == 1) {
        PERFWARNING_LOG("Use plain for ncols==1");
        p.impl = GHOST_IMPLEMENTATION_PLAIN;
    }
    if (p.xcols % 4 || p.vcols % 4) {
        PERFWARNING_LOG("Use plain for non-multiple of four");
        p.impl = GHOST_IMPLEMENTATION_SSE;
    }
    if (p.xcols % 2 || p.vcols % 2) {
        PERFWARNING_LOG("Use plain for non-even column count");
        p.impl = GHOST_IMPLEMENTATION_PLAIN;
    }

    void *xptr, *vptr, *wptr;
    ghost_densemat_valptr(x,&xptr);
    ghost_densemat_valptr(v,&vptr);
    ghost_densemat_valptr(w,&wptr);

    if (p.impl == GHOST_IMPLEMENTATION_SSE) {
        if (!IS_ALIGNED(xptr,16) || !IS_ALIGNED(vptr,16) || !IS_ALIGNED(wptr,16)) {
            p.alignment = GHOST_UNALIGNED;
        }
    }
    if (p.impl == GHOST_IMPLEMENTATION_AVX) {
        if (!IS_ALIGNED(xptr,32) || !IS_ALIGNED(vptr,32) || !IS_ALIGNED(wptr,32)) {
            p.alignment = GHOST_UNALIGNED;
        }
    }
    kernel = ghost_tsmm_kernels[p];

    if (!kernel) {
        PERFWARNING_LOG("Try kernel with fixed xcols and arbitrary vcols");
        p.xcols = x->traits.ncols;
        p.vcols = -1;
        kernel = ghost_tsmm_kernels[p];
    }

    if (!kernel) {
        PERFWARNING_LOG("Try kernel with fixed vcols and arbitrary xcols");
        p.xcols = -1;
        p.vcols = v->traits.ncols;
        kernel = ghost_tsmm_kernels[p];
    }

    if (!kernel) {
        PERFWARNING_LOG("Try kernel with arbitrary block sizes");
        p.xcols = -1;
        p.vcols = -1;
        kernel = ghost_tsmm_kernels[p];
    }

    if (!kernel) {
        PERFWARNING_LOG("Try plain implementation");
        p.impl = GHOST_IMPLEMENTATION_PLAIN;
        kernel = ghost_tsmm_kernels[p];
    }

    if (!kernel) {
        INFO_LOG("Could not find TSMM kernel with %d %d %d %d!",p.impl,p.dt,p.xcols,p.vcols);
        return GHOST_ERR_NOT_IMPLEMENTED;
    }

    ret = kernel(x,v,w,alpha,beta);

#ifdef GHOST_HAVE_INSTR_TIMING
    ghost_gemm_perf_args_t tsmm_perfargs;
    tsmm_perfargs.xcols = p.xcols;
    tsmm_perfargs.vcols = p.vcols;
    tsmm_perfargs.vrows = v->context->gnrows;
    tsmm_perfargs.dt = x->traits.datatype;
    ghost_timing_set_perfFunc(__ghost_functag,ghost_tsmm_perf_GBs,(void *)&tsmm_perfargs,sizeof(tsmm_perfargs),"GB/s");
    ghost_timing_set_perfFunc(__ghost_functag,ghost_gemm_perf_GFs,(void *)&tsmm_perfargs,sizeof(tsmm_perfargs),"GF/s");
#endif

    GHOST_FUNC_EXIT(GHOST_FUNCTYPE_MATH);

    return ret;
}

int ghost_tsmm_perf_GBs(double *perf, double time, void *varg)
{
    size_t size;
    ghost_gemm_perf_args_t arg = *(ghost_gemm_perf_args_t *)varg;

    ghost_datatype_size(&size,arg.dt);

    *perf = size*(arg.vrows*arg.vcols+arg.vrows*arg.xcols+arg.vcols*arg.xcols)/1.e9/time;

    return 0;
}

<commit_msg>try fixed block sizes again after fallback to plain implementation<commit_after>#include "ghost/config.h"
#include "ghost/types.h"
#include "ghost/densemat.h"
#include "ghost/util.h"
#include "ghost/math.h"
#include "ghost/tsmm.h"
#include "ghost/tsmm_gen.h"
#include "ghost/tsmm_avx_gen.h"
#include "ghost/tsmm_sse_gen.h"

#include <map>

using namespace std;

static bool operator<(const ghost_tsmm_parameters_t &a, const ghost_tsmm_parameters_t &b)
{
    return ghost_hash(a.dt,a.xcols,ghost_hash(a.vcols,a.impl,0)) < ghost_hash(b.dt,b.xcols,ghost_hash(b.vcols,b.impl,0));
}

static map<ghost_tsmm_parameters_t, ghost_tsmm_kernel_t> ghost_tsmm_kernels;

ghost_error_t ghost_tsmm_valid(ghost_densemat_t *x, ghost_densemat_t *v,  const char * transv,
ghost_densemat_t *w, const char *transw, void *alpha, void *beta, int reduce, int printerror)
{
    if (x->traits.datatype != v->traits.datatype || x->traits.datatype != w->traits.datatype) {
        if (printerror) {
            ERROR_LOG("Different data types!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (x == v) {
        if (printerror) {
           ERROR_LOG("x must not be equal to v!");
        }
        return GHOST_ERR_INVALID_ARG;
    }

    if (w->traits.storage != GHOST_DENSEMAT_COLMAJOR) {
        if (printerror) {
           ERROR_LOG("w must be stored col-major!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (x->traits.storage != GHOST_DENSEMAT_ROWMAJOR) {
        if (printerror) {
            ERROR_LOG("x must be stored row-major!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (v->traits.storage != GHOST_DENSEMAT_ROWMAJOR) {
        if (printerror) {
           ERROR_LOG("v must be stored row-major!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if ((x->traits.flags & GHOST_DENSEMAT_SCATTERED) || (v->traits.flags & GHOST_DENSEMAT_SCATTERED) || (w->traits.flags & GHOST_DENSEMAT_SCATTERED)) {
        if (printerror) {
            ERROR_LOG("Scattered views not supported!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (reduce != GHOST_GEMM_NO_REDUCE) {
        if (printerror) {
            ERROR_LOG("Only NO_REDUCE valid!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (strncasecmp(transv,"N",1)) {
        if (printerror) {
            ERROR_LOG("v must not be transposed!");
        }
        return GHOST_ERR_INVALID_ARG;
    }
    if (strncasecmp(transw,"N",1)) {
        if (printerror) {
            ERROR_LOG("w must not be transposed!");
        }
        return GHOST_ERR_INVALID_ARG;
    }

    UNUSED(alpha);
    UNUSED(beta);

    return GHOST_SUCCESS;
}

ghost_error_t ghost_tsmm(ghost_densemat_t *x, ghost_densemat_t *v, ghost_densemat_t *w, void *alpha, void *beta)
{
    GHOST_FUNC_ENTER(GHOST_FUNCTYPE_MATH);
    ghost_error_t ret;

    if ((ret = ghost_tsmm_valid(x,v,"N",w,"N",alpha,beta,GHOST_GEMM_NO_REDUCE,1)) != GHOST_SUCCESS) {
        return ret;
    }

    if (ghost_tsmm_kernels.empty()) {
#include "tsmm.def"
#include "tsmm_avx.def"
#include "tsmm_sse.def"
    }

    ghost_tsmm_parameters_t p;
    ghost_tsmm_kernel_t kernel = NULL;
#ifdef GHOST_HAVE_MIC
    p.impl = GHOST_IMPLEMENTATION_MIC;
#elif defined(GHOST_HAVE_AVX)
    p.impl = GHOST_IMPLEMENTATION_AVX;
#elif defined(GHOST_HAVE_SSE)
    p.impl = GHOST_IMPLEMENTATION_SSE;
#else
    p.impl = GHOST_IMPLEMENTATION_PLAIN;
#endif

    p.alignment = GHOST_ALIGNED;
    p.dt = x->traits.datatype;

    p.xcols = x->traits.ncols;
    p.vcols = v->traits.ncols;
    if (p.xcols == 2) {
#ifdef GHOST_HAVE_SSE
        PERFWARNING_LOG("Use SSE for ncols==2");
        p.impl = GHOST_IMPLEMENTATION_SSE;
#endif
    }
    if (p.xcols == 1) {
        PERFWARNING_LOG("Use plain for ncols==1");
        p.impl = GHOST_IMPLEMENTATION_PLAIN;
    }
    if (p.xcols % 4 || p.vcols % 4) {
        PERFWARNING_LOG("Use plain for non-multiple of four");
        p.impl = GHOST_IMPLEMENTATION_SSE;
    }
    if (p.xcols % 2 || p.vcols % 2) {
        PERFWARNING_LOG("Use plain for non-even column count");
        p.impl = GHOST_IMPLEMENTATION_PLAIN;
    }

    void *xptr, *vptr, *wptr;
    ghost_densemat_valptr(x,&xptr);
    ghost_densemat_valptr(v,&vptr);
    ghost_densemat_valptr(w,&wptr);

    if (p.impl == GHOST_IMPLEMENTATION_SSE) {
        if (!IS_ALIGNED(xptr,16) || !IS_ALIGNED(vptr,16) || !IS_ALIGNED(wptr,16)) {
            p.alignment = GHOST_UNALIGNED;
        }
    }
    if (p.impl == GHOST_IMPLEMENTATION_AVX) {
        if (!IS_ALIGNED(xptr,32) || !IS_ALIGNED(vptr,32) || !IS_ALIGNED(wptr,32)) {
            p.alignment = GHOST_UNALIGNED;
        }
    }
    kernel = ghost_tsmm_kernels[p];

    if (!kernel) {
        PERFWARNING_LOG("Try kernel with fixed xcols and arbitrary vcols");
        p.xcols = x->traits.ncols;
        p.vcols = -1;
        kernel = ghost_tsmm_kernels[p];
    }

    if (!kernel) {
        PERFWARNING_LOG("Try kernel with fixed vcols and arbitrary xcols");
        p.xcols = -1;
        p.vcols = v->traits.ncols;
        kernel = ghost_tsmm_kernels[p];
    }

    if (!kernel) {
        PERFWARNING_LOG("Try kernel with arbitrary block sizes");
        p.xcols = -1;
        p.vcols = -1;
        kernel = ghost_tsmm_kernels[p];
    }

    if (!kernel) {
        PERFWARNING_LOG("Try plain implementation");
        p.impl = GHOST_IMPLEMENTATION_PLAIN;
        p.xcols = x->traits.ncols;
        p.vcols = v->traits.ncols;
        kernel = ghost_tsmm_kernels[p];
    }
    if (!kernel) {
        PERFWARNING_LOG("Try kernel with fixed xcols and arbitrary vcols");
        p.xcols = x->traits.ncols;
        p.vcols = -1;
        kernel = ghost_tsmm_kernels[p];
    }

    if (!kernel) {
        PERFWARNING_LOG("Try kernel with fixed vcols and arbitrary xcols");
        p.xcols = -1;
        p.vcols = v->traits.ncols;
        kernel = ghost_tsmm_kernels[p];
    }

    if (!kernel) {
        PERFWARNING_LOG("Try kernel with arbitrary block sizes");
        p.xcols = -1;
        p.vcols = -1;
        kernel = ghost_tsmm_kernels[p];
    }

    if (!kernel) {
        INFO_LOG("Could not find TSMM kernel with %d %d %d %d!",p.impl,p.dt,p.xcols,p.vcols);
        return GHOST_ERR_NOT_IMPLEMENTED;
    }

    ret = kernel(x,v,w,alpha,beta);

#ifdef GHOST_HAVE_INSTR_TIMING
    ghost_gemm_perf_args_t tsmm_perfargs;
    tsmm_perfargs.xcols = p.xcols;
    tsmm_perfargs.vcols = p.vcols;
    tsmm_perfargs.vrows = v->context->gnrows;
    tsmm_perfargs.dt = x->traits.datatype;
    ghost_timing_set_perfFunc(__ghost_functag,ghost_tsmm_perf_GBs,(void *)&tsmm_perfargs,sizeof(tsmm_perfargs),"GB/s");
    ghost_timing_set_perfFunc(__ghost_functag,ghost_gemm_perf_GFs,(void *)&tsmm_perfargs,sizeof(tsmm_perfargs),"GF/s");
#endif

    GHOST_FUNC_EXIT(GHOST_FUNCTYPE_MATH);

    return ret;
}

int ghost_tsmm_perf_GBs(double *perf, double time, void *varg)
{
    size_t size;
    ghost_gemm_perf_args_t arg = *(ghost_gemm_perf_args_t *)varg;

    ghost_datatype_size(&size,arg.dt);

    *perf = size*(arg.vrows*arg.vcols+arg.vrows*arg.xcols+arg.vcols*arg.xcols)/1.e9/time;

    return 0;
}

<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2021 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#define CAF_SUITE detail.private_thread_pool

#include "caf/detail/private_thread_pool.hpp"

#include "core-test.hpp"

#include "caf/detail/private_thread.hpp"

using namespace caf;

CAF_TEST_FIXTURE_SCOPE(private_thread_pool_tests, test_coordinator_fixture<>)

SCENARIO("private threads count towards detached actors") {
  GIVEN("an actor system with a private thread pool") {
    detail::private_thread* t1 = nullptr;
    detail::private_thread* t2 = nullptr;
    WHEN("acquiring new private threads") {
      THEN("the detached_actors counter increases") {
        CHECK_EQ(sys.detached_actors(), 0u);
        t1 = sys.acquire_private_thread();
        CHECK_EQ(sys.detached_actors(), 1u);
        t2 = sys.acquire_private_thread();
        CHECK_EQ(sys.detached_actors(), 2u);
      }
    }
    WHEN("releasing the private threads") {
      THEN("the detached_actors counter eventually decreases again") {
        auto next_value = [this, old_value{2u}]() mutable {
          using namespace std::literals::chrono_literals;
          size_t result = 0;
          while ((result = sys.detached_actors()) == old_value)
            std::this_thread::sleep_for(1ms);
          old_value = result;
          return result;
        };
        sys.release_private_thread(t2);
        CHECK_EQ(next_value(), 1u);
        sys.release_private_thread(t1);
        CHECK_EQ(next_value(), 0u);
      }
    }
  }
}

SCENARIO("private threads rerun their resumable when it returns resume_later") {
  struct testee : resumable {
    std::atomic<size_t> runs = 0;
    std::atomic<size_t> refs_added = 0;
    std::atomic<size_t> refs_released = 0;
    subtype_t subtype() const override {
      return resumable::function_object;
    }
    resume_result resume(execution_unit*, size_t) override {
      return ++runs < 2 ? resumable::resume_later : resumable::done;
    }
    void intrusive_ptr_add_ref_impl() override {
      ++refs_added;
    }
    void intrusive_ptr_release_impl() override {
      ++refs_released;
    }
  };
  GIVEN("a resumable f and a private thread t") {
    testee f;
    auto t = sys.acquire_private_thread();
    WHEN("when resuming f with t") {
      t->resume(&f);
      THEN("t calls resume until f returns something other than resume_later") {
        using namespace std::literals::chrono_literals;
        sys.release_private_thread(t);
        while (sys.detached_actors() != 0)
          std::this_thread::sleep_for(1ms);
        CHECK_EQ(f.runs, 2u);
        CHECK_EQ(f.refs_added, 0u);
        CHECK_EQ(f.refs_released, 1u);
      }
    }
  }
}

CAF_TEST_FIXTURE_SCOPE_END()
<commit_msg>Fix race in private_thread_pool unit test<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2021 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#define CAF_SUITE detail.private_thread_pool

#include "caf/detail/private_thread_pool.hpp"

#include "core-test.hpp"

#include "caf/detail/private_thread.hpp"

using namespace caf;

CAF_TEST_FIXTURE_SCOPE(private_thread_pool_tests, test_coordinator_fixture<>)

SCENARIO("private threads count towards detached actors") {
  GIVEN("an actor system with a private thread pool") {
    detail::private_thread* t1 = nullptr;
    detail::private_thread* t2 = nullptr;
    WHEN("acquiring new private threads") {
      THEN("the detached_actors counter increases") {
        CHECK_EQ(sys.detached_actors(), 0u);
        t1 = sys.acquire_private_thread();
        CHECK_EQ(sys.detached_actors(), 1u);
        t2 = sys.acquire_private_thread();
        CHECK_EQ(sys.detached_actors(), 2u);
      }
    }
    WHEN("releasing the private threads") {
      THEN("the detached_actors counter eventually decreases again") {
        auto next_value = [this, old_value{2u}]() mutable {
          using namespace std::literals::chrono_literals;
          size_t result = 0;
          while ((result = sys.detached_actors()) == old_value)
            std::this_thread::sleep_for(1ms);
          old_value = result;
          return result;
        };
        sys.release_private_thread(t2);
        CHECK_EQ(next_value(), 1u);
        sys.release_private_thread(t1);
        CHECK_EQ(next_value(), 0u);
      }
    }
  }
}

SCENARIO("private threads rerun their resumable when it returns resume_later") {
  struct testee : resumable {
    std::atomic<size_t> runs = 0;
    std::atomic<size_t> refs_added = 0;
    std::atomic<size_t> refs_released = 0;
    subtype_t subtype() const override {
      return resumable::function_object;
    }
    resume_result resume(execution_unit*, size_t) override {
      return ++runs < 2 ? resumable::resume_later : resumable::done;
    }
    void intrusive_ptr_add_ref_impl() override {
      ++refs_added;
    }
    void intrusive_ptr_release_impl() override {
      ++refs_released;
    }
  };
  GIVEN("a resumable f and a private thread t") {
    testee f;
    auto t = sys.acquire_private_thread();
    WHEN("when resuming f with t") {
      t->resume(&f);
      THEN("t calls resume until f returns something other than resume_later") {
        using namespace std::literals::chrono_literals;
        sys.release_private_thread(t);
        while (f.runs != 2u)
          std::this_thread::sleep_for(1ms);
        while (sys.detached_actors() != 0)
          std::this_thread::sleep_for(1ms);
        CHECK_EQ(f.refs_added, 0u);
        CHECK_EQ(f.refs_released, 1u);
      }
    }
  }
}

CAF_TEST_FIXTURE_SCOPE_END()
<|endoftext|>


<commit_before>/*
 * ReciprocalConn.cpp
 *
 *  For two connections with transpose geometries (the pre of one has the
 *  same geometry as the post of another and vice versa).  They are not
 *  forced to be each other's transpose, but there is a penalty term
 *  on the L2 norm of the difference between it and its reciprocal's
 *  transpose, of the amount
 *  r/2 * || W/f_W - (W_recip)'/f_{W_recip} ||^2.
 *
 *  r is the parameter reciprocalFidelityCoeff
 *  W is the weights and W_recip is the weights of the reciprocal connection
 *  f_W and f_{W_recip} are the number of features of each connection.
 *
 *  The connection forces the normalization method to be that for each feature,
 *  the sum across kernels (number of features of reciprocal connection) is unity.
 *
 *  Dividing by f_W and f_{W_recip} therefore makes the sum of all matrix
 *  entries of each connection 1.
 *
 *  This is still under the assumption that nxp = nyp = 1.
 *
 *  There is also the ability to specify an additional penalty of the form
 *  dW/dt += slownessPost * slownessPre', by setting slownessFlag to true
 *  and specifying slownessPre and slownessPost layers.
 *
 *  The name comes from the motivation of including a slowness term on
 *  ReciprocalConns, but the slowness interpretation is not within ReciprocalConn.
 *  IncrementLayer was written so that setting A to an IncrementLayer, and
 *  having a layer B be the post of a clone of the ReciprocalConn, setting
 *  slownessPre to A and slownessPost to B would implement a slowness term.
 *
 *  Created on: Feb 16, 2012
 *      Author: pschultz
 */

#include "ReciprocalConn.hpp"

namespace PV {

ReciprocalConn::ReciprocalConn() {
   initialize_base();

}

ReciprocalConn::ReciprocalConn(const char * name, HyPerCol * hc,
         HyPerLayer * pre, HyPerLayer * post,
         const char * filename, InitWeights * weightInit) {
   initialize_base();
   initialize(name, hc, pre, post, filename, weightInit);
}

int ReciprocalConn::initialize_base() {
   updateRulePre = NULL;
   updateRulePost = NULL;
   reciprocalWgts = NULL;
   slownessPre = NULL;
   slownessPost = NULL;
   sums = NULL;
   normalizeNoiseLevel = 0.0;
   return PV_SUCCESS;
}

int ReciprocalConn::initialize(const char * name, HyPerCol * hc,
      HyPerLayer * pre, HyPerLayer * post,
      const char * filename, InitWeights * weightInit) {
   int status = PV_SUCCESS;
   status = KernelConn::initialize(name, hc, pre, post, filename, weightInit);
   PVParams * params = hc->parameters();
   relaxationRate = params->value(name, "relaxationRate", 1.0f);
   reciprocalFidelityCoeff = params->value(name, "reciprocalFidelityCoeff", 1.0f);

   status = initParameterLayer("updateRulePre", &updateRulePre, pre) == PV_SUCCESS ? status : PV_FAILURE;
   status = initParameterLayer("updateRulePost", &updateRulePost, post) == PV_SUCCESS ? status : PV_FAILURE;

   slownessFlag = params->value(name, "slownessFlag", false)!=0;
   if( slownessFlag ) {
      status = initParameterLayer("slownessPre", &slownessPre, NULL) == PV_SUCCESS ? status : PV_FAILURE;
      status = initParameterLayer("slownessPost", &slownessPost, NULL) == PV_SUCCESS ? status : PV_FAILURE;
   }

   reciprocalWgtsName = params->stringValue(name, "reciprocalWgts");
   if( reciprocalWgtsName == NULL || reciprocalWgtsName[0] == '0') {
      fprintf(stderr, "ReciprocalConn \"%s\": reciprocalWgts must be defined.\n", name);
      status = PV_FAILURE;
   }
   if( status != PV_SUCCESS ) abort();

   return status;
}

int ReciprocalConn::initParameterLayer(const char * parametername, HyPerLayer ** layerPtr, HyPerLayer * defaultlayer) {
   int status = PV_SUCCESS;
   PVParams * params = parent->parameters();
   const char * layerName = params->stringValue(name, parametername);
   if( layerName == NULL || layerName[0] == '0') {
      if( defaultlayer == NULL ) {
         fprintf(stderr, "ReciprocalConn \"%s\": parameter \"%s\" was not defined and no default was specified.\n", name, parametername);
         status = PV_FAILURE;
      }
      else {
         fprintf(stdout, "ReciprocalConn \"%s\": parameter \"%s\" set to \"s\"\n", name, defaultlayer->getName());
         *layerPtr = defaultlayer;
      }
   }
   else {
      *layerPtr = parent->getLayerFromName(layerName);
      if( *layerPtr == NULL ) {
         fprintf(stderr, "ReciprocalConn \"%s\" parameter \"%s\": value \"%s\" is not the name of a layer.\n", name, parametername, layerName);
         status = PV_FAILURE;
      }
   }
   return status;
}

int ReciprocalConn::initNormalize() {
   PVParams * params = parent->parameters();
   normalizeNoiseLevel = params->value(name, "normalizeNoiseLevel", normalizeNoiseLevel);
   nxUnitCellPost = zUnitCellSize(postSynapticLayer()->getXScale(), preSynapticLayer()->getXScale());
   nyUnitCellPost = zUnitCellSize(postSynapticLayer()->getYScale(), preSynapticLayer()->getYScale());
   nfUnitCellPost = fPatchSize();
   sizeUnitCellPost = nxUnitCellPost*nyUnitCellPost*nfUnitCellPost;
   sums = (pvdata_t *) malloc(sizeUnitCellPost*sizeof(pvdata_t));
   if( sums == NULL ) abort();

   return PV_SUCCESS;
}

int ReciprocalConn::updateState(float timef, float dt) {
   // Need to set reciprocalWgts the first time updateState is called, so that each ReciprocalConn in a pair can define the other
   // If it was set in initialize, the second would not have been defined when the first was called.
   if( reciprocalWgts == NULL) {
      setReciprocalWgts(reciprocalWgtsName);
   }
   int status = KernelConn::updateState(timef, dt);
   return status;
}

int ReciprocalConn::setReciprocalWgts(const char * recipName) {
   int status = PV_SUCCESS;
   if( status == PV_SUCCESS && recipName == NULL ) {
      status = PV_FAILURE;
      fprintf(stderr, "ReciprocalConn \"%s\": setReciprocalWgts called with null argument.\n", name);
   }

   HyPerConn * c;
   if( status == PV_SUCCESS ) {
      c = parent->getConnFromName(recipName);
      if( c == NULL) {
         status = PV_FAILURE;
         fprintf(stderr, "ReciprocalConn \"%s\": reciprocalWgts \"%s\" could not be found.\n", name, recipName);
      }
   }
   if( status == PV_SUCCESS && reciprocalWgts != NULL) {
      if(c != reciprocalWgts) {
         fprintf(stderr, "ReciprocalConn \"%s\": setReciprocalWgts called with reciprocalWgts already set.\n", name);
         status = PV_FAILURE;
      }
   }
   if( status == PV_SUCCESS && reciprocalWgts == NULL ) {
      reciprocalWgts = dynamic_cast<ReciprocalConn *>(parent->getConnFromName(recipName));
      if( reciprocalWgts == NULL ) {
         fprintf(stderr, "ReciprocalConn \"%s\": reciprocalWgts \"%s\" is not a ReciprocalConn.\n", name, recipName);
         status = PV_FAILURE;
      }
   }
   return status;
}

int ReciprocalConn::update_dW(int axonID) {
   int nExt = preSynapticLayer()->getNumExtended();
   int numKernelIndices = getNumDataPatches();
   int delay = getDelay(axonID);
   const pvdata_t * preactbuf = updateRulePre->getLayerData(delay);
   const pvdata_t * postactbuf = updateRulePost->getLayerData(delay);
   const pvdata_t * slownessprebuf = getSlownessFlag() ? slownessPre->getLayerData(delay) : NULL;
   const pvdata_t * slownesspostbuf = getSlownessFlag() ? slownessPost->getLayerData(delay) : NULL;

   int sya = (post->getLayerLoc()->nf * (post->getLayerLoc()->nx + 2*post->getLayerLoc()->nb));
   for(int kExt=0; kExt<nExt;kExt++) {
      PVPatch * weights = getWeights(kExt,axonID);
      size_t offset = getAPostOffset(kExt, axonID);
      int ny = weights->ny;
      int nk = weights->nx * nfp;
      pvdata_t preact = preactbuf[kExt];
      const pvdata_t * postactRef = &postactbuf[offset];
      pvdata_t * dwdata = get_dwData(axonID, kExt);
      int lineoffsetw = 0;
      int lineoffseta = 0;
      for( int y=0; y<ny; y++ ) {
         for( int k=0; k<nk; k++ ) {
            dwdata[lineoffsetw + k] += updateRule_dW(preact, postactRef[lineoffseta+k]);
         }
         lineoffsetw += syp;
         lineoffseta += sya;
      }
      if( slownessFlag ) {
         preact = slownessprebuf[kExt];
         postactRef = &slownesspostbuf[offset];

         int lineoffsetw = 0;
         int lineoffseta = 0;
         for( int y=0; y<ny; y++ ) {
            for( int k=0; k<nk; k++ ) {
               dwdata[lineoffsetw + k] += updateRule_dW(preact, postactRef[lineoffseta+k]);
            }
            lineoffsetw += syp;
            lineoffseta += sya;
         }
      }
   }
   if( reciprocalFidelityCoeff ) {
      for( int k=0; k<numKernelIndices; k++) {
         const pvdata_t * wdata = get_wDataHead(axonID, k);
         pvdata_t * dwdata = get_dwDataHead(axonID, k);
         int n=0;
         for( int y=0; y<nyp; y++ ) { for( int x=0; x<nxp; x++) { for( int f=0; f<nfp; f++ ) {
            int xRecip, yRecip, fRecip, kRecip;
            getReciprocalWgtCoordinates(x, y, f, k, &xRecip, &yRecip, &fRecip, &kRecip);
            const pvdata_t * recipwdata = reciprocalWgts->get_wDataHead(axonID, kRecip);
            int nRecip = kIndex(xRecip, yRecip, fRecip, reciprocalWgts->xPatchSize(), reciprocalWgts->yPatchSize(), reciprocalWgts->fPatchSize());
            dwdata[n] -= reciprocalFidelityCoeff/nfp*(wdata[n]/nfp-recipwdata[nRecip]/reciprocalWgts->fPatchSize());
            n++;
         }}}
      }
   }

   // Divide by (numNeurons/numKernels)
   int divisor = pre->getNumNeurons()/numKernelIndices;
   assert( divisor*numKernelIndices == pre->getNumNeurons() );
   for( int kernelindex=0; kernelindex<numKernelIndices; kernelindex++ ) {
      int numpatchitems = nxp * nyp * nfp;
      pvdata_t * dwpatchdata = get_dwDataHead(axonID,kernelindex);
      for( int n=0; n<numpatchitems; n++ ) {
         dwpatchdata[n] /= divisor;
      }
   }

   lastUpdateTime = parent->simulationTime();
   return PV_SUCCESS;
}

int ReciprocalConn::updateWeights(int arborID) {
   lastUpdateTime = parent->simulationTime();
   // add dw to w
      for( int k=0; k<nxp*nyp*nfp*getNumDataPatches(); k++ ) {
         get_wDataStart(arborID)[k] += relaxationRate*parent->getDeltaTime()*get_dwDataStart(arborID)[k];
      }
   int status = PV_SUCCESS;
   pvdata_t * arborstart = get_wDataStart(arborID);
   for( int k=0; k<nxp*nyp*nfp*getNumDataPatches(); k++ ) {
      if( arborstart[k] < 0 ) arborstart[k] = 0;
   }
   return status;
}

int ReciprocalConn::normalizeWeights(PVPatch ** patches, pvdata_t ** dataStart, int numPatches, int arborID) {
   assert(arborID == 0); // TODO how to handle arbors.  Do I need to sum over arbors or handle each arbor independently?
   int status = PV_SUCCESS;
   assert( numPatches == getNumDataPatches() );

   if( normalizeNoiseLevel == 0.0f ) {
      for( int k=0; k<sizeUnitCellPost; k++ ) sums[k] = 0;
   }
   else {
      for( int k=0; k<sizeUnitCellPost; k++ ) sums[k] = normalizeNoiseLevel * pv_random_prob();
   }

   for( int kernel=0; kernel<numPatches; kernel++ ) {
      pvdata_t * kernelData = &dataStart[arborID][kernel*nxp*nyp*nfp];
      for( int y=0; y<yPatchSize(); y++ ) {
         int yInCell = y % nyUnitCellPost;
         for( int x=0; x<xPatchSize(); x++ ) {
            int xInCell = x % nxUnitCellPost;
            for( int f=0; f<fPatchSize(); f++ ) {
               int idxInCell = kIndex(xInCell, yInCell, f, nxUnitCellPost, nyUnitCellPost, nfUnitCellPost);
               sums[idxInCell] += kernelData[kIndex(x,y,f,nxp,nyp,nfp)];
            }
         }
      }
   }

   for( int kernel=0; kernel<numPatches; kernel++ ) {
      pvdata_t * kernelData = &dataStart[arborID][kernel*nxp*nyp*nfp];
      for( int y=0; y<yPatchSize(); y++ ) {
         int yInCell = y % nyUnitCellPost;
         for( int x=0; x<xPatchSize(); x++ ) {
            int xInCell = x % nxUnitCellPost;
            for( int f=0; f<fPatchSize(); f++ ) {
               int idxInCell = kIndex(xInCell, yInCell, f, nxUnitCellPost, nyUnitCellPost, nfUnitCellPost);
               kernelData[kIndex(x,y,f,nxp,nyp,nfp)] /= sums[idxInCell];
            }
         }
      }
   }
   return status;
}

ReciprocalConn::~ReciprocalConn() {
   free(sums); sums=NULL;
}

} /* namespace PV */
<commit_msg>weights->offset fix for ReciprocalConn::update_dW<commit_after>/*
 * ReciprocalConn.cpp
 *
 *  For two connections with transpose geometries (the pre of one has the
 *  same geometry as the post of another and vice versa).  They are not
 *  forced to be each other's transpose, but there is a penalty term
 *  on the L2 norm of the difference between it and its reciprocal's
 *  transpose, of the amount
 *  r/2 * || W/f_W - (W_recip)'/f_{W_recip} ||^2.
 *
 *  r is the parameter reciprocalFidelityCoeff
 *  W is the weights and W_recip is the weights of the reciprocal connection
 *  f_W and f_{W_recip} are the number of features of each connection.
 *
 *  The connection forces the normalization method to be that for each feature,
 *  the sum across kernels (number of features of reciprocal connection) is unity.
 *
 *  Dividing by f_W and f_{W_recip} therefore makes the sum of all matrix
 *  entries of each connection 1.
 *
 *  This is still under the assumption that nxp = nyp = 1.
 *
 *  There is also the ability to specify an additional penalty of the form
 *  dW/dt += slownessPost * slownessPre', by setting slownessFlag to true
 *  and specifying slownessPre and slownessPost layers.
 *
 *  The name comes from the motivation of including a slowness term on
 *  ReciprocalConns, but the slowness interpretation is not within ReciprocalConn.
 *  IncrementLayer was written so that setting A to an IncrementLayer, and
 *  having a layer B be the post of a clone of the ReciprocalConn, setting
 *  slownessPre to A and slownessPost to B would implement a slowness term.
 *
 *  Created on: Feb 16, 2012
 *      Author: pschultz
 */

#include "ReciprocalConn.hpp"

namespace PV {

ReciprocalConn::ReciprocalConn() {
   initialize_base();

}

ReciprocalConn::ReciprocalConn(const char * name, HyPerCol * hc,
         HyPerLayer * pre, HyPerLayer * post,
         const char * filename, InitWeights * weightInit) {
   initialize_base();
   initialize(name, hc, pre, post, filename, weightInit);
}

int ReciprocalConn::initialize_base() {
   updateRulePre = NULL;
   updateRulePost = NULL;
   reciprocalWgts = NULL;
   slownessPre = NULL;
   slownessPost = NULL;
   sums = NULL;
   normalizeNoiseLevel = 0.0;
   return PV_SUCCESS;
}

int ReciprocalConn::initialize(const char * name, HyPerCol * hc,
      HyPerLayer * pre, HyPerLayer * post,
      const char * filename, InitWeights * weightInit) {
   int status = PV_SUCCESS;
   status = KernelConn::initialize(name, hc, pre, post, filename, weightInit);
   PVParams * params = hc->parameters();
   relaxationRate = params->value(name, "relaxationRate", 1.0f);
   reciprocalFidelityCoeff = params->value(name, "reciprocalFidelityCoeff", 1.0f);

   status = initParameterLayer("updateRulePre", &updateRulePre, pre) == PV_SUCCESS ? status : PV_FAILURE;
   status = initParameterLayer("updateRulePost", &updateRulePost, post) == PV_SUCCESS ? status : PV_FAILURE;

   slownessFlag = params->value(name, "slownessFlag", false)!=0;
   if( slownessFlag ) {
      status = initParameterLayer("slownessPre", &slownessPre, NULL) == PV_SUCCESS ? status : PV_FAILURE;
      status = initParameterLayer("slownessPost", &slownessPost, NULL) == PV_SUCCESS ? status : PV_FAILURE;
   }

   reciprocalWgtsName = params->stringValue(name, "reciprocalWgts");
   if( reciprocalWgtsName == NULL || reciprocalWgtsName[0] == '0') {
      fprintf(stderr, "ReciprocalConn \"%s\": reciprocalWgts must be defined.\n", name);
      status = PV_FAILURE;
   }
   if( status != PV_SUCCESS ) abort();

   return status;
}

int ReciprocalConn::initParameterLayer(const char * parametername, HyPerLayer ** layerPtr, HyPerLayer * defaultlayer) {
   int status = PV_SUCCESS;
   PVParams * params = parent->parameters();
   const char * layerName = params->stringValue(name, parametername);
   if( layerName == NULL || layerName[0] == '0') {
      if( defaultlayer == NULL ) {
         fprintf(stderr, "ReciprocalConn \"%s\": parameter \"%s\" was not defined and no default was specified.\n", name, parametername);
         status = PV_FAILURE;
      }
      else {
         fprintf(stdout, "ReciprocalConn \"%s\": parameter \"%s\" set to \"s\"\n", name, defaultlayer->getName());
         *layerPtr = defaultlayer;
      }
   }
   else {
      *layerPtr = parent->getLayerFromName(layerName);
      if( *layerPtr == NULL ) {
         fprintf(stderr, "ReciprocalConn \"%s\" parameter \"%s\": value \"%s\" is not the name of a layer.\n", name, parametername, layerName);
         status = PV_FAILURE;
      }
   }
   return status;
}

int ReciprocalConn::initNormalize() {
   PVParams * params = parent->parameters();
   normalizeNoiseLevel = params->value(name, "normalizeNoiseLevel", normalizeNoiseLevel);
   nxUnitCellPost = zUnitCellSize(postSynapticLayer()->getXScale(), preSynapticLayer()->getXScale());
   nyUnitCellPost = zUnitCellSize(postSynapticLayer()->getYScale(), preSynapticLayer()->getYScale());
   nfUnitCellPost = fPatchSize();
   sizeUnitCellPost = nxUnitCellPost*nyUnitCellPost*nfUnitCellPost;
   sums = (pvdata_t *) malloc(sizeUnitCellPost*sizeof(pvdata_t));
   if( sums == NULL ) abort();

   return PV_SUCCESS;
}

int ReciprocalConn::updateState(float timef, float dt) {
   // Need to set reciprocalWgts the first time updateState is called, so that each ReciprocalConn in a pair can define the other
   // If it was set in initialize, the second would not have been defined when the first was called.
   if( reciprocalWgts == NULL) {
      setReciprocalWgts(reciprocalWgtsName);
   }
   int status = KernelConn::updateState(timef, dt);
   return status;
}

int ReciprocalConn::setReciprocalWgts(const char * recipName) {
   int status = PV_SUCCESS;
   if( status == PV_SUCCESS && recipName == NULL ) {
      status = PV_FAILURE;
      fprintf(stderr, "ReciprocalConn \"%s\": setReciprocalWgts called with null argument.\n", name);
   }

   HyPerConn * c;
   if( status == PV_SUCCESS ) {
      c = parent->getConnFromName(recipName);
      if( c == NULL) {
         status = PV_FAILURE;
         fprintf(stderr, "ReciprocalConn \"%s\": reciprocalWgts \"%s\" could not be found.\n", name, recipName);
      }
   }
   if( status == PV_SUCCESS && reciprocalWgts != NULL) {
      if(c != reciprocalWgts) {
         fprintf(stderr, "ReciprocalConn \"%s\": setReciprocalWgts called with reciprocalWgts already set.\n", name);
         status = PV_FAILURE;
      }
   }
   if( status == PV_SUCCESS && reciprocalWgts == NULL ) {
      reciprocalWgts = dynamic_cast<ReciprocalConn *>(parent->getConnFromName(recipName));
      if( reciprocalWgts == NULL ) {
         fprintf(stderr, "ReciprocalConn \"%s\": reciprocalWgts \"%s\" is not a ReciprocalConn.\n", name, recipName);
         status = PV_FAILURE;
      }
   }
   return status;
}

int ReciprocalConn::update_dW(int axonID) {
   int nExt = preSynapticLayer()->getNumExtended();
   int numKernelIndices = getNumDataPatches();
   int delay = getDelay(axonID);
   const pvdata_t * preactbuf = updateRulePre->getLayerData(delay);
   const pvdata_t * postactbuf = updateRulePost->getLayerData(delay);
   const pvdata_t * slownessprebuf = getSlownessFlag() ? slownessPre->getLayerData(delay) : NULL;
   const pvdata_t * slownesspostbuf = getSlownessFlag() ? slownessPost->getLayerData(delay) : NULL;

   int sya = (post->getLayerLoc()->nf * (post->getLayerLoc()->nx + 2*post->getLayerLoc()->nb));
   for(int kExt=0; kExt<nExt;kExt++) {
      PVPatch * weights = getWeights(kExt,axonID);
      size_t offset = getAPostOffset(kExt, axonID);
      int ny = weights->ny;
      int nk = weights->nx * nfp;
      pvdata_t preact = preactbuf[kExt];
      const pvdata_t * postactRef = &postactbuf[offset];
      pvdata_t * dwdata = get_dwData(axonID, kExt);
      int lineoffsetw = weights->offset;
      int lineoffseta = 0;
      for( int y=0; y<ny; y++ ) {
         for( int k=0; k<nk; k++ ) {
            dwdata[lineoffsetw + k] += updateRule_dW(preact, postactRef[lineoffseta+k]);
         }
         lineoffsetw += syp;
         lineoffseta += sya;
      }
      if( slownessFlag ) {
         preact = slownessprebuf[kExt];
         postactRef = &slownesspostbuf[offset];

         int lineoffsetw = weights->offset;
         int lineoffseta = 0;
         for( int y=0; y<ny; y++ ) {
            for( int k=0; k<nk; k++ ) {
               dwdata[lineoffsetw + k] += updateRule_dW(preact, postactRef[lineoffseta+k]);
            }
            lineoffsetw += syp;
            lineoffseta += sya;
         }
      }
   }
   if( reciprocalFidelityCoeff ) {
      for( int k=0; k<numKernelIndices; k++) {
         const pvdata_t * wdata = get_wDataHead(axonID, k);
         pvdata_t * dwdata = get_dwDataHead(axonID, k);
         int n=0;
         for( int y=0; y<nyp; y++ ) { for( int x=0; x<nxp; x++) { for( int f=0; f<nfp; f++ ) {
            int xRecip, yRecip, fRecip, kRecip;
            getReciprocalWgtCoordinates(x, y, f, k, &xRecip, &yRecip, &fRecip, &kRecip);
            const pvdata_t * recipwdata = reciprocalWgts->get_wDataHead(axonID, kRecip);
            int nRecip = kIndex(xRecip, yRecip, fRecip, reciprocalWgts->xPatchSize(), reciprocalWgts->yPatchSize(), reciprocalWgts->fPatchSize());
            dwdata[n] -= reciprocalFidelityCoeff/nfp*(wdata[n]/nfp-recipwdata[nRecip]/reciprocalWgts->fPatchSize());
            n++;
         }}}
      }
   }

   // Divide by (numNeurons/numKernels)
   int divisor = pre->getNumNeurons()/numKernelIndices;
   assert( divisor*numKernelIndices == pre->getNumNeurons() );
   for( int kernelindex=0; kernelindex<numKernelIndices; kernelindex++ ) {
      int numpatchitems = nxp * nyp * nfp;
      pvdata_t * dwpatchdata = get_dwDataHead(axonID,kernelindex);
      for( int n=0; n<numpatchitems; n++ ) {
         dwpatchdata[n] /= divisor;
      }
   }

   lastUpdateTime = parent->simulationTime();
   return PV_SUCCESS;
}

int ReciprocalConn::updateWeights(int arborID) {
   lastUpdateTime = parent->simulationTime();
   // add dw to w
      for( int k=0; k<nxp*nyp*nfp*getNumDataPatches(); k++ ) {
         get_wDataStart(arborID)[k] += relaxationRate*parent->getDeltaTime()*get_dwDataStart(arborID)[k];
      }
   int status = PV_SUCCESS;
   pvdata_t * arborstart = get_wDataStart(arborID);
   for( int k=0; k<nxp*nyp*nfp*getNumDataPatches(); k++ ) {
      if( arborstart[k] < 0 ) arborstart[k] = 0;
   }
   return status;
}

int ReciprocalConn::normalizeWeights(PVPatch ** patches, pvdata_t ** dataStart, int numPatches, int arborID) {
   assert(arborID == 0); // TODO how to handle arbors.  Do I need to sum over arbors or handle each arbor independently?
   int status = PV_SUCCESS;
   assert( numPatches == getNumDataPatches() );

   if( normalizeNoiseLevel == 0.0f ) {
      for( int k=0; k<sizeUnitCellPost; k++ ) sums[k] = 0;
   }
   else {
      for( int k=0; k<sizeUnitCellPost; k++ ) sums[k] = normalizeNoiseLevel * pv_random_prob();
   }

   for( int kernel=0; kernel<numPatches; kernel++ ) {
      pvdata_t * kernelData = &dataStart[arborID][kernel*nxp*nyp*nfp];
      for( int y=0; y<yPatchSize(); y++ ) {
         int yInCell = y % nyUnitCellPost;
         for( int x=0; x<xPatchSize(); x++ ) {
            int xInCell = x % nxUnitCellPost;
            for( int f=0; f<fPatchSize(); f++ ) {
               int idxInCell = kIndex(xInCell, yInCell, f, nxUnitCellPost, nyUnitCellPost, nfUnitCellPost);
               sums[idxInCell] += kernelData[kIndex(x,y,f,nxp,nyp,nfp)];
            }
         }
      }
   }

   for( int kernel=0; kernel<numPatches; kernel++ ) {
      pvdata_t * kernelData = &dataStart[arborID][kernel*nxp*nyp*nfp];
      for( int y=0; y<yPatchSize(); y++ ) {
         int yInCell = y % nyUnitCellPost;
         for( int x=0; x<xPatchSize(); x++ ) {
            int xInCell = x % nxUnitCellPost;
            for( int f=0; f<fPatchSize(); f++ ) {
               int idxInCell = kIndex(xInCell, yInCell, f, nxUnitCellPost, nyUnitCellPost, nfUnitCellPost);
               kernelData[kIndex(x,y,f,nxp,nyp,nfp)] /= sums[idxInCell];
            }
         }
      }
   }
   return status;
}

ReciprocalConn::~ReciprocalConn() {
   free(sums); sums=NULL;
}

} /* namespace PV */
<|endoftext|>


<commit_before>/*
 * Copyright 2013-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/Memory.h>

#include <algorithm>
#include <limits>
#include <type_traits>
#include <utility>

#include <glog/logging.h>

#include <folly/String.h>
#include <folly/memory/Arena.h>
#include <folly/portability/GMock.h>
#include <folly/portability/GTest.h>

using namespace folly;

static constexpr std::size_t kTooBig = std::max(
    std::size_t{std::numeric_limits<uint32_t>::max()},
    std::size_t{1} << (8 * sizeof(std::size_t) - 14));

TEST(aligned_malloc, examples) {
  auto trial = [](size_t align) {
    auto const ptr = aligned_malloc(1, align);
    return (aligned_free(ptr), uintptr_t(ptr));
  };

  if (!kIsSanitize) { // asan allocator raises SIGABRT instead
    EXPECT_EQ(EINVAL, (trial(2), errno)) << "too small";
    EXPECT_EQ(EINVAL, (trial(513), errno)) << "not power of two";
  }

  EXPECT_EQ(0, trial(512) % 512);
  EXPECT_EQ(0, trial(8192) % 8192);
}

TEST(make_unique, compatible_with_std_make_unique) {
  //  HACK: To enforce that `folly::` is imported here.
  to_shared_ptr(std::unique_ptr<std::string>());

  using namespace std;
  make_unique<string>("hello, world");
}

TEST(to_weak_ptr, example) {
  auto s = std::make_shared<int>(17);
  EXPECT_EQ(1, s.use_count());
  EXPECT_EQ(2, (to_weak_ptr(s).lock(), s.use_count())) << "lvalue";
  EXPECT_EQ(3, (to_weak_ptr(decltype(s)(s)).lock(), s.use_count())) << "rvalue";
}

TEST(SysAllocator, equality) {
  using Alloc = SysAllocator<float>;
  Alloc const a, b;
  EXPECT_TRUE(a == b);
  EXPECT_FALSE(a != b);
}

TEST(SysAllocator, allocate_unique) {
  using Alloc = SysAllocator<float>;
  Alloc const alloc;
  auto ptr = allocate_unique<float>(alloc, 3.);
  EXPECT_EQ(3., *ptr);
}

TEST(SysAllocator, vector) {
  using Alloc = SysAllocator<float>;
  Alloc const alloc;
  std::vector<float, Alloc> nums(alloc);
  nums.push_back(3.);
  nums.push_back(5.);
  EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
}

TEST(SysAllocator, bad_alloc) {
  using Alloc = SysAllocator<float>;
  Alloc const alloc;
  std::vector<float, Alloc> nums(alloc);
  if (!kIsSanitize) {
    EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
  }
}

TEST(AlignedSysAllocator, equality_fixed) {
  using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  Alloc const a, b;
  EXPECT_TRUE(a == b);
  EXPECT_FALSE(a != b);
}

TEST(AlignedSysAllocator, allocate_unique_fixed) {
  using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  Alloc const alloc;
  auto ptr = allocate_unique<float>(alloc, 3.);
  EXPECT_EQ(3., *ptr);
  EXPECT_EQ(0, std::uintptr_t(ptr.get()) % 1024);
}

TEST(AlignedSysAllocator, vector_fixed) {
  using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  Alloc const alloc;
  std::vector<float, Alloc> nums(alloc);
  nums.push_back(3.);
  nums.push_back(5.);
  EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
  EXPECT_EQ(0, std::uintptr_t(nums.data()) % 1024);
}

TEST(AlignedSysAllocator, bad_alloc_fixed) {
  using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  Alloc const alloc;
  std::vector<float, Alloc> nums(alloc);
  if (!kIsSanitize) {
    EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
  }
}

TEST(AlignedSysAllocator, equality_default) {
  using Alloc = AlignedSysAllocator<float>;
  Alloc const a(1024), b(1024), c(512);
  EXPECT_TRUE(a == b);
  EXPECT_FALSE(a != b);
  EXPECT_FALSE(a == c);
  EXPECT_TRUE(a != c);
}

TEST(AlignedSysAllocator, allocate_unique_default) {
  using Alloc = AlignedSysAllocator<float>;
  Alloc const alloc(1024);
  auto ptr = allocate_unique<float>(alloc, 3.);
  EXPECT_EQ(3., *ptr);
  EXPECT_EQ(0, std::uintptr_t(ptr.get()) % 1024);
}

TEST(AlignedSysAllocator, vector_default) {
  using Alloc = AlignedSysAllocator<float>;
  Alloc const alloc(1024);
  std::vector<float, Alloc> nums(alloc);
  nums.push_back(3.);
  nums.push_back(5.);
  EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
  EXPECT_EQ(0, std::uintptr_t(nums.data()) % 1024);
}

TEST(AlignedSysAllocator, bad_alloc_default) {
  using Alloc = AlignedSysAllocator<float>;
  Alloc const alloc(1024);
  std::vector<float, Alloc> nums(alloc);
  if (!kIsSanitize) {
    EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
  }
}

TEST(allocate_sys_buffer, compiles) {
  auto buf = allocate_sys_buffer(256);
  //  Freed at the end of the scope.
}

namespace {
template <typename T>
struct TestAlloc1 : SysAllocator<T> {
  template <typename U, typename... Args>
  void construct(U* p, Args&&... args) {
    ::new (static_cast<void*>(p)) U(std::forward<Args>(args)...);
  }
};

template <typename T>
struct TestAlloc2 : TestAlloc1<T> {
  template <typename U>
  void destroy(U* p) {
    p->~U();
  }
};

template <typename T>
struct TestAlloc3 : TestAlloc2<T> {
  using folly_has_default_object_construct = std::true_type;
};

template <typename T>
struct TestAlloc4 : TestAlloc3<T> {
  using folly_has_default_object_destroy = std::true_type;
};

template <typename T>
struct TestAlloc5 : SysAllocator<T> {
  using folly_has_default_object_construct = std::true_type;
  using folly_has_default_object_destroy = std::false_type;
};
} // namespace

TEST(AllocatorObjectLifecycleTraits, compiles) {
  using A = std::allocator<int>;
  using S = std::string;

  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<A, int, int>::value, "");
  static_assert(folly::AllocatorHasDefaultObjectConstruct<A, S, S>::value, "");

  static_assert(folly::AllocatorHasDefaultObjectDestroy<A, int>::value, "");
  static_assert(folly::AllocatorHasDefaultObjectDestroy<A, S>::value, "");

  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<
          folly::AlignedSysAllocator<int>,
          int,
          int>::value,
      "");
  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<
          folly::AlignedSysAllocator<int>,
          S,
          S>::value,
      "");

  static_assert(
      folly::AllocatorHasDefaultObjectDestroy<
          folly::AlignedSysAllocator<int>,
          int>::value,
      "");
  static_assert(
      folly::AllocatorHasDefaultObjectDestroy<
          folly::AlignedSysAllocator<int>,
          S>::value,
      "");

  static_assert(
      !folly::AllocatorHasDefaultObjectConstruct<TestAlloc1<S>, S, S>::value,
      "");
  static_assert(
      folly::AllocatorHasDefaultObjectDestroy<TestAlloc1<S>, S>::value, "");

  static_assert(
      !folly::AllocatorHasDefaultObjectConstruct<TestAlloc2<S>, S, S>::value,
      "");
  static_assert(
      !folly::AllocatorHasDefaultObjectDestroy<TestAlloc2<S>, S>::value, "");

  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<TestAlloc3<S>, S, S>::value,
      "");
  static_assert(
      !folly::AllocatorHasDefaultObjectDestroy<TestAlloc3<S>, S>::value, "");

  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<TestAlloc4<S>, S, S>::value,
      "");
  static_assert(
      folly::AllocatorHasDefaultObjectDestroy<TestAlloc4<S>, S>::value, "");

  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<TestAlloc5<S>, S, S>::value,
      "");
  static_assert(
      !folly::AllocatorHasDefaultObjectDestroy<TestAlloc5<S>, S>::value, "");
}

template <typename C>
static void test_enable_shared_from_this(std::shared_ptr<C> sp) {
  ASSERT_EQ(1l, sp.use_count());

  // Test shared_from_this().
  std::shared_ptr<C> sp2 = sp->shared_from_this();
  ASSERT_EQ(sp, sp2);

  // Test weak_from_this().
  std::weak_ptr<C> wp = sp->weak_from_this();
  ASSERT_EQ(sp, wp.lock());
  sp.reset();
  sp2.reset();
  ASSERT_EQ(nullptr, wp.lock());

  // Test shared_from_this() and weak_from_this() on object not owned by a
  // shared_ptr. Undefined in C++14 but well-defined in C++17. Also known to
  // work with libstdc++ >= 20150123. Feel free to add other standard library
  // versions where the behavior is known.
#if __cplusplus >= 201700L || __GLIBCXX__ >= 20150123L
  C stack_resident;
  ASSERT_THROW(stack_resident.shared_from_this(), std::bad_weak_ptr);
  ASSERT_TRUE(stack_resident.weak_from_this().expired());
#endif
}

TEST(enable_shared_from_this, compatible_with_std_enable_shared_from_this) {
  // Compile-time compatibility.
  class C_std : public std::enable_shared_from_this<C_std> {};
  class C_folly : public folly::enable_shared_from_this<C_folly> {};
  static_assert(
      noexcept(std::declval<C_std>().shared_from_this()) ==
          noexcept(std::declval<C_folly>().shared_from_this()),
      "");
  static_assert(
      noexcept(std::declval<C_std const>().shared_from_this()) ==
          noexcept(std::declval<C_folly const>().shared_from_this()),
      "");
  static_assert(noexcept(std::declval<C_folly>().weak_from_this()), "");
  static_assert(noexcept(std::declval<C_folly const>().weak_from_this()), "");

  // Runtime compatibility.
  test_enable_shared_from_this(std::make_shared<C_folly>());
  test_enable_shared_from_this(std::make_shared<C_folly const>());
}
<commit_msg>fix MemoryTest for platforms without constexpr std::max<commit_after>/*
 * Copyright 2013-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/Memory.h>

#include <limits>
#include <type_traits>
#include <utility>

#include <glog/logging.h>

#include <folly/ConstexprMath.h>
#include <folly/String.h>
#include <folly/memory/Arena.h>
#include <folly/portability/GMock.h>
#include <folly/portability/GTest.h>

using namespace folly;

static constexpr std::size_t kTooBig = folly::constexpr_max(
    std::size_t{std::numeric_limits<uint32_t>::max()},
    std::size_t{1} << (8 * sizeof(std::size_t) - 14));

TEST(aligned_malloc, examples) {
  auto trial = [](size_t align) {
    auto const ptr = aligned_malloc(1, align);
    return (aligned_free(ptr), uintptr_t(ptr));
  };

  if (!kIsSanitize) { // asan allocator raises SIGABRT instead
    EXPECT_EQ(EINVAL, (trial(2), errno)) << "too small";
    EXPECT_EQ(EINVAL, (trial(513), errno)) << "not power of two";
  }

  EXPECT_EQ(0, trial(512) % 512);
  EXPECT_EQ(0, trial(8192) % 8192);
}

TEST(make_unique, compatible_with_std_make_unique) {
  //  HACK: To enforce that `folly::` is imported here.
  to_shared_ptr(std::unique_ptr<std::string>());

  using namespace std;
  make_unique<string>("hello, world");
}

TEST(to_weak_ptr, example) {
  auto s = std::make_shared<int>(17);
  EXPECT_EQ(1, s.use_count());
  EXPECT_EQ(2, (to_weak_ptr(s).lock(), s.use_count())) << "lvalue";
  EXPECT_EQ(3, (to_weak_ptr(decltype(s)(s)).lock(), s.use_count())) << "rvalue";
}

TEST(SysAllocator, equality) {
  using Alloc = SysAllocator<float>;
  Alloc const a, b;
  EXPECT_TRUE(a == b);
  EXPECT_FALSE(a != b);
}

TEST(SysAllocator, allocate_unique) {
  using Alloc = SysAllocator<float>;
  Alloc const alloc;
  auto ptr = allocate_unique<float>(alloc, 3.);
  EXPECT_EQ(3., *ptr);
}

TEST(SysAllocator, vector) {
  using Alloc = SysAllocator<float>;
  Alloc const alloc;
  std::vector<float, Alloc> nums(alloc);
  nums.push_back(3.);
  nums.push_back(5.);
  EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
}

TEST(SysAllocator, bad_alloc) {
  using Alloc = SysAllocator<float>;
  Alloc const alloc;
  std::vector<float, Alloc> nums(alloc);
  if (!kIsSanitize) {
    EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
  }
}

TEST(AlignedSysAllocator, equality_fixed) {
  using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  Alloc const a, b;
  EXPECT_TRUE(a == b);
  EXPECT_FALSE(a != b);
}

TEST(AlignedSysAllocator, allocate_unique_fixed) {
  using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  Alloc const alloc;
  auto ptr = allocate_unique<float>(alloc, 3.);
  EXPECT_EQ(3., *ptr);
  EXPECT_EQ(0, std::uintptr_t(ptr.get()) % 1024);
}

TEST(AlignedSysAllocator, vector_fixed) {
  using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  Alloc const alloc;
  std::vector<float, Alloc> nums(alloc);
  nums.push_back(3.);
  nums.push_back(5.);
  EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
  EXPECT_EQ(0, std::uintptr_t(nums.data()) % 1024);
}

TEST(AlignedSysAllocator, bad_alloc_fixed) {
  using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  Alloc const alloc;
  std::vector<float, Alloc> nums(alloc);
  if (!kIsSanitize) {
    EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
  }
}

TEST(AlignedSysAllocator, equality_default) {
  using Alloc = AlignedSysAllocator<float>;
  Alloc const a(1024), b(1024), c(512);
  EXPECT_TRUE(a == b);
  EXPECT_FALSE(a != b);
  EXPECT_FALSE(a == c);
  EXPECT_TRUE(a != c);
}

TEST(AlignedSysAllocator, allocate_unique_default) {
  using Alloc = AlignedSysAllocator<float>;
  Alloc const alloc(1024);
  auto ptr = allocate_unique<float>(alloc, 3.);
  EXPECT_EQ(3., *ptr);
  EXPECT_EQ(0, std::uintptr_t(ptr.get()) % 1024);
}

TEST(AlignedSysAllocator, vector_default) {
  using Alloc = AlignedSysAllocator<float>;
  Alloc const alloc(1024);
  std::vector<float, Alloc> nums(alloc);
  nums.push_back(3.);
  nums.push_back(5.);
  EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
  EXPECT_EQ(0, std::uintptr_t(nums.data()) % 1024);
}

TEST(AlignedSysAllocator, bad_alloc_default) {
  using Alloc = AlignedSysAllocator<float>;
  Alloc const alloc(1024);
  std::vector<float, Alloc> nums(alloc);
  if (!kIsSanitize) {
    EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
  }
}

TEST(allocate_sys_buffer, compiles) {
  auto buf = allocate_sys_buffer(256);
  //  Freed at the end of the scope.
}

namespace {
template <typename T>
struct TestAlloc1 : SysAllocator<T> {
  template <typename U, typename... Args>
  void construct(U* p, Args&&... args) {
    ::new (static_cast<void*>(p)) U(std::forward<Args>(args)...);
  }
};

template <typename T>
struct TestAlloc2 : TestAlloc1<T> {
  template <typename U>
  void destroy(U* p) {
    p->~U();
  }
};

template <typename T>
struct TestAlloc3 : TestAlloc2<T> {
  using folly_has_default_object_construct = std::true_type;
};

template <typename T>
struct TestAlloc4 : TestAlloc3<T> {
  using folly_has_default_object_destroy = std::true_type;
};

template <typename T>
struct TestAlloc5 : SysAllocator<T> {
  using folly_has_default_object_construct = std::true_type;
  using folly_has_default_object_destroy = std::false_type;
};
} // namespace

TEST(AllocatorObjectLifecycleTraits, compiles) {
  using A = std::allocator<int>;
  using S = std::string;

  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<A, int, int>::value, "");
  static_assert(folly::AllocatorHasDefaultObjectConstruct<A, S, S>::value, "");

  static_assert(folly::AllocatorHasDefaultObjectDestroy<A, int>::value, "");
  static_assert(folly::AllocatorHasDefaultObjectDestroy<A, S>::value, "");

  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<
          folly::AlignedSysAllocator<int>,
          int,
          int>::value,
      "");
  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<
          folly::AlignedSysAllocator<int>,
          S,
          S>::value,
      "");

  static_assert(
      folly::AllocatorHasDefaultObjectDestroy<
          folly::AlignedSysAllocator<int>,
          int>::value,
      "");
  static_assert(
      folly::AllocatorHasDefaultObjectDestroy<
          folly::AlignedSysAllocator<int>,
          S>::value,
      "");

  static_assert(
      !folly::AllocatorHasDefaultObjectConstruct<TestAlloc1<S>, S, S>::value,
      "");
  static_assert(
      folly::AllocatorHasDefaultObjectDestroy<TestAlloc1<S>, S>::value, "");

  static_assert(
      !folly::AllocatorHasDefaultObjectConstruct<TestAlloc2<S>, S, S>::value,
      "");
  static_assert(
      !folly::AllocatorHasDefaultObjectDestroy<TestAlloc2<S>, S>::value, "");

  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<TestAlloc3<S>, S, S>::value,
      "");
  static_assert(
      !folly::AllocatorHasDefaultObjectDestroy<TestAlloc3<S>, S>::value, "");

  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<TestAlloc4<S>, S, S>::value,
      "");
  static_assert(
      folly::AllocatorHasDefaultObjectDestroy<TestAlloc4<S>, S>::value, "");

  static_assert(
      folly::AllocatorHasDefaultObjectConstruct<TestAlloc5<S>, S, S>::value,
      "");
  static_assert(
      !folly::AllocatorHasDefaultObjectDestroy<TestAlloc5<S>, S>::value, "");
}

template <typename C>
static void test_enable_shared_from_this(std::shared_ptr<C> sp) {
  ASSERT_EQ(1l, sp.use_count());

  // Test shared_from_this().
  std::shared_ptr<C> sp2 = sp->shared_from_this();
  ASSERT_EQ(sp, sp2);

  // Test weak_from_this().
  std::weak_ptr<C> wp = sp->weak_from_this();
  ASSERT_EQ(sp, wp.lock());
  sp.reset();
  sp2.reset();
  ASSERT_EQ(nullptr, wp.lock());

  // Test shared_from_this() and weak_from_this() on object not owned by a
  // shared_ptr. Undefined in C++14 but well-defined in C++17. Also known to
  // work with libstdc++ >= 20150123. Feel free to add other standard library
  // versions where the behavior is known.
#if __cplusplus >= 201700L || __GLIBCXX__ >= 20150123L
  C stack_resident;
  ASSERT_THROW(stack_resident.shared_from_this(), std::bad_weak_ptr);
  ASSERT_TRUE(stack_resident.weak_from_this().expired());
#endif
}

TEST(enable_shared_from_this, compatible_with_std_enable_shared_from_this) {
  // Compile-time compatibility.
  class C_std : public std::enable_shared_from_this<C_std> {};
  class C_folly : public folly::enable_shared_from_this<C_folly> {};
  static_assert(
      noexcept(std::declval<C_std>().shared_from_this()) ==
          noexcept(std::declval<C_folly>().shared_from_this()),
      "");
  static_assert(
      noexcept(std::declval<C_std const>().shared_from_this()) ==
          noexcept(std::declval<C_folly const>().shared_from_this()),
      "");
  static_assert(noexcept(std::declval<C_folly>().weak_from_this()), "");
  static_assert(noexcept(std::declval<C_folly const>().weak_from_this()), "");

  // Runtime compatibility.
  test_enable_shared_from_this(std::make_shared<C_folly>());
  test_enable_shared_from_this(std::make_shared<C_folly const>());
}
<|endoftext|>


<commit_before>#include "gui/preferencesmodel.h"
#include "utilities/qutils.h"
#include "changebase.h"
#include "upgrades.h"
#include "upgrade.h"
#include "log.h"

namespace Modules
{

Upgrade::Upgrade()
{
	connect(this, &QQuickItem::parentChanged, this, &Upgrade::registerStep);
}

void Upgrade::applyUpgrade(const std::string & function, const Version & version, Json::Value & analysesJson, UpgradeMsgs & msgs, StepsTaken & stepsTaken)
{
	if(function != fq(functionName()))	throw upgradeError("Wrong Upgrade being applied, was looking for function '"	+ function				+ "' but this upgrade is for: '" + fq(functionName())		+ "'");
	if(version	!= fromVersion())		throw upgradeError("Wrong Upgrade being applied, was looking for version '"		+ version.asString()	+ "' but this upgrade is for: '" + fromVersion().asString() + "'");

	StepTaken	fromStep(		{fq(module()),	fq(functionName()),		fromVersion()	}),
				aboutToStep(	{fq(module()),	fq(newFunctionName()),	toVersion()		});

	stepsTaken.insert(fromStep); //We want to remember where we come from

	if(stepsTaken.count(aboutToStep) > 0)
		throw upgradeError(fq("Aborting upgrade because a loop was detected!\n\nIf " +	toString() + " is taken, eventually it is reached again.\n\nThis should definitely not happen, perhaps the module author of '" + module() + "' can be of assistance"));

	analysesJson["name"]							= fq(newFunctionName());
	analysesJson["dynamicModule"]["analysisEntry"]	= fq(newFunctionName());
	analysesJson["dynamicModule"]["moduleVersion"]	= toVersion().asString();

	//No loop so far, lets apply some changes for this step
	for(ChangeBase * change : _changes)
		try
		{
			Log::log() << "Checking if condition for change " << change->toString() << " is satisfied, ";
			if(change->conditionSatisfied(analysesJson["options"]))
			{
				Log::log(false) << "it is and applying the change!" << std::endl;
				change->applyUpgrade(analysesJson["options"], msgs);
			}
			else
				Log::log(false) << "it isn't and moving on." << std::endl;
		}
		catch(upgradeError & error)
		{
			//If we are not in developermode it would be better to keep going instead of crashing the whole upgradeprocess
			if(PreferencesModel::prefs()->developerMode())
				throw error;
			else
				Log::log() << "Change had a problem: " << error.what() << std::endl;
		}
}

QString Upgrade::toString()
{
	return "Module '" + module() + "' from version '" + fromVersionQ() + "' to '" + toVersionQ() + "' for function '" + functionName() + "'" + ( newFunctionName() == functionName() ? "" : " being renamed to '" + newFunctionName() + "'");
}

Version Upgrade::fromVersion() const
{
	try
	{
		return Version(fq(_fromVersion));
	}
	catch(Version::encodingError & e)
	{
		throw upgradeError("Incorrect from version: '" + fq(_fromVersion) + "' supplied to Upgrade...");
	}
}

Version Upgrade::toVersion() const
{
	try
	{
		return Version(fq(_toVersion));
	}
	catch(Version::encodingError & e)
	{
		throw upgradeError("Incorrect to version: '" + fq(_toVersion) + "' supplied to Upgrade...");
	}
}

QString Upgrade::module() const
{
	return _upgrades ? _upgrades->module() : "???";
}

void Upgrade::registerStep(QQuickItem * parent)
{
	Upgrades * upgrades = dynamic_cast<Upgrades*>(parent);

	if(!upgrades && parent)
		throw upgradeLoadError(fq(toString()), "An Upgrade Item must always be a child of Upgrades");

	if(upgrades != _upgrades)
	{
		if(_upgrades)
			_upgrades->removeStep(this);

		_upgrades = upgrades;

		if(_upgrades)
			_upgrades->addStep(this);
	}
}

Upgrade::~Upgrade()
{
	if(_upgrades)
		_upgrades->removeStep(this);
}

void Upgrade::addChange(ChangeBase *change)
{
	for(ChangeBase * c : _changes)
		if(c == change) return;

	_changes.push_back(change);
}

void Upgrade::removeChange(ChangeBase *change)
{
	for(size_t i=_changes.size(); i>0; i--)
		if(_changes[i-1] == change)
			_changes.erase(_changes.begin() + i - 1);
}

void Upgrade::setFromVersionQ(QString fromVersion)
{
	if (_fromVersion == fromVersion)
		return;

	_fromVersion = fromVersion;
	emit fromVersionChanged();
}

void Upgrade::setToVersionQ(QString toVersion)
{
	if (_toVersion == toVersion)
		return;

	_toVersion = toVersion;
	emit toVersionChanged();
}

void Upgrade::setFunctionName(QString functionName)
{
	if (_functionName == functionName)
		return;

	_functionName = functionName;
	emit functionNameChanged(_functionName);
}

void Upgrade::setNewFunctionName(QString newFunctionName)
{
	if (_newFunctionName == newFunctionName)
		return;

	_newFunctionName = newFunctionName;
	emit newFunctionNameChanged(_newFunctionName);
}

}
<commit_msg>Fix version check in qml upgrader<commit_after>#include "gui/preferencesmodel.h"
#include "utilities/qutils.h"
#include "changebase.h"
#include "upgrades.h"
#include "upgrade.h"
#include "log.h"

namespace Modules
{

Upgrade::Upgrade()
{
	connect(this, &QQuickItem::parentChanged, this, &Upgrade::registerStep);
}

void Upgrade::applyUpgrade(const std::string & function, const Version & version, Json::Value & analysesJson, UpgradeMsgs & msgs, StepsTaken & stepsTaken)
{
	if(function != fq(functionName()))	throw upgradeError(fq(tr("Wrong Upgrade being applied, was looking for function '%1' but this upgrade is for: '%2'").arg(tq(function)).arg(functionName())));
	if(version	>  fromVersion())		throw upgradeError(fq(tr("Wrong Upgrade being applied, was looking for version '%1' but this upgrade is for: '%2' or lower").arg(tq(version.asString())).arg(tq(fromVersion().asString()))));

	StepTaken	fromStep(		{fq(module()),	fq(functionName()),		fromVersion()	}),
				aboutToStep(	{fq(module()),	fq(newFunctionName()),	toVersion()		});

	stepsTaken.insert(fromStep); //We want to remember where we come from

	if(stepsTaken.count(aboutToStep) > 0)
		throw upgradeError(fq(tr("Aborting upgrade because a loop was detected!\n\nIf %1 is taken, eventually it is reached again.\n\nThis should definitely not happen, perhaps the module author of '%2' can be of assistance").arg(toString()).arg(module())));

	analysesJson["name"]							= fq(newFunctionName());
	analysesJson["dynamicModule"]["analysisEntry"]	= fq(newFunctionName());
	analysesJson["dynamicModule"]["moduleVersion"]	= toVersion().asString();

	//No loop so far, lets apply some changes for this step
	for(ChangeBase * change : _changes)
		try
		{
			Log::log() << "Checking if condition for change " << change->toString() << " is satisfied, ";
			if(change->conditionSatisfied(analysesJson["options"]))
			{
				Log::log(false) << "it is and applying the change!" << std::endl;
				change->applyUpgrade(analysesJson["options"], msgs);
			}
			else
				Log::log(false) << "it isn't and moving on." << std::endl;
		}
		catch(upgradeError & error)
		{
			//If we are not in developermode it would be better to keep going instead of crashing the whole upgradeprocess
			if(PreferencesModel::prefs()->developerMode())
				throw error;
			else
				Log::log() << "Change had a problem: " << error.what() << std::endl;
		}
}

QString Upgrade::toString()
{
	return "Module '" + module() + "' from version '" + fromVersionQ() + "' to '" + toVersionQ() + "' for function '" + functionName() + "'" + ( newFunctionName() == functionName() ? "" : " being renamed to '" + newFunctionName() + "'");
}

Version Upgrade::fromVersion() const
{
	try
	{
		return Version(fq(_fromVersion));
	}
	catch(Version::encodingError & e)
	{
		throw upgradeError("Incorrect from version: '" + fq(_fromVersion) + "' supplied to Upgrade...");
	}
}

Version Upgrade::toVersion() const
{
	try
	{
		return Version(fq(_toVersion));
	}
	catch(Version::encodingError & e)
	{
		throw upgradeError("Incorrect to version: '" + fq(_toVersion) + "' supplied to Upgrade...");
	}
}

QString Upgrade::module() const
{
	return _upgrades ? _upgrades->module() : "???";
}

void Upgrade::registerStep(QQuickItem * parent)
{
	Upgrades * upgrades = dynamic_cast<Upgrades*>(parent);

	if(!upgrades && parent)
		throw upgradeLoadError(fq(toString()), "An Upgrade Item must always be a child of Upgrades");

	if(upgrades != _upgrades)
	{
		if(_upgrades)
			_upgrades->removeStep(this);

		_upgrades = upgrades;

		if(_upgrades)
			_upgrades->addStep(this);
	}
}

Upgrade::~Upgrade()
{
	if(_upgrades)
		_upgrades->removeStep(this);
}

void Upgrade::addChange(ChangeBase *change)
{
	for(ChangeBase * c : _changes)
		if(c == change) return;

	_changes.push_back(change);
}

void Upgrade::removeChange(ChangeBase *change)
{
	for(size_t i=_changes.size(); i>0; i--)
		if(_changes[i-1] == change)
			_changes.erase(_changes.begin() + i - 1);
}

void Upgrade::setFromVersionQ(QString fromVersion)
{
	if (_fromVersion == fromVersion)
		return;

	_fromVersion = fromVersion;
	emit fromVersionChanged();
}

void Upgrade::setToVersionQ(QString toVersion)
{
	if (_toVersion == toVersion)
		return;

	_toVersion = toVersion;
	emit toVersionChanged();
}

void Upgrade::setFunctionName(QString functionName)
{
	if (_functionName == functionName)
		return;

	_functionName = functionName;
	emit functionNameChanged(_functionName);
}

void Upgrade::setNewFunctionName(QString newFunctionName)
{
	if (_newFunctionName == newFunctionName)
		return;

	_newFunctionName = newFunctionName;
	emit newFunctionNameChanged(_newFunctionName);
}

}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "xwalk/extensions/common/xwalk_external_instance.h"

#include <string>
#include "base/logging.h"
#include "xwalk/extensions/common/xwalk_external_extension.h"
#include "xwalk/extensions/common/xwalk_external_adapter.h"

namespace xwalk {
namespace extensions {

XWalkExternalInstance::XWalkExternalInstance(
    XWalkExternalExtension* extension, XW_Instance xw_instance)
    : xw_instance_(xw_instance),
      extension_(extension),
      instance_data_(NULL),
      is_handling_sync_msg_(false) {
  XWalkExternalAdapter::GetInstance()->RegisterInstance(this);
  XW_CreatedInstanceCallback callback = extension_->created_instance_callback_;
  if (callback)
    callback(xw_instance_);
}

XWalkExternalInstance::~XWalkExternalInstance() {
  XW_DestroyedInstanceCallback callback =
      extension_->destroyed_instance_callback_;
  if (callback)
    callback(xw_instance_);
  XWalkExternalAdapter::GetInstance()->UnregisterInstance(this);
}

void XWalkExternalInstance::HandleMessage(scoped_ptr<base::Value> msg) {
  XW_HandleMessageCallback callback = extension_->handle_msg_callback_;
  if (!callback) {
    LOG(WARNING) << "Ignoring message sent for external extension '"
                 << extension_->name() << "' which doesn't support it.";
    return;
  }

  std::string string_msg;
  msg->GetAsString(&string_msg);
  callback(xw_instance_, string_msg.c_str());
}

void XWalkExternalInstance::HandleSyncMessage(scoped_ptr<base::Value> msg) {
  XW_HandleSyncMessageCallback callback = extension_->handle_sync_msg_callback_;
  if (!callback) {
    LOG(WARNING) << "Ignoring sync message sent for external extension '"
                 << extension_->name() << "' which doesn't support it.";
    return;
  }

  std::string string_msg;
  msg->GetAsString(&string_msg);

  callback(xw_instance_, string_msg.c_str());
}

void XWalkExternalInstance::CoreSetInstanceData(void* data) {
  instance_data_ = data;
}

void* XWalkExternalInstance::CoreGetInstanceData() {
  return instance_data_;
}

void XWalkExternalInstance::MessagingPostMessage(const char* msg) {
  PostMessageToJS(scoped_ptr<base::Value>(new base::StringValue(msg)));
}

void XWalkExternalInstance::SyncMessagingSetSyncReply(const char* reply) {
  SendSyncReplyToJS(scoped_ptr<base::Value>(new base::StringValue(reply)));
}

}  // namespace extensions
}  // namespace xwalk
<commit_msg>extensions: Check GetString()'s return value.<commit_after>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "xwalk/extensions/common/xwalk_external_instance.h"

#include <string>
#include "base/logging.h"
#include "xwalk/extensions/common/xwalk_external_extension.h"
#include "xwalk/extensions/common/xwalk_external_adapter.h"

namespace xwalk {
namespace extensions {

XWalkExternalInstance::XWalkExternalInstance(
    XWalkExternalExtension* extension, XW_Instance xw_instance)
    : xw_instance_(xw_instance),
      extension_(extension),
      instance_data_(NULL),
      is_handling_sync_msg_(false) {
  XWalkExternalAdapter::GetInstance()->RegisterInstance(this);
  XW_CreatedInstanceCallback callback = extension_->created_instance_callback_;
  if (callback)
    callback(xw_instance_);
}

XWalkExternalInstance::~XWalkExternalInstance() {
  XW_DestroyedInstanceCallback callback =
      extension_->destroyed_instance_callback_;
  if (callback)
    callback(xw_instance_);
  XWalkExternalAdapter::GetInstance()->UnregisterInstance(this);
}

void XWalkExternalInstance::HandleMessage(scoped_ptr<base::Value> msg) {
  XW_HandleMessageCallback callback = extension_->handle_msg_callback_;
  if (!callback) {
    LOG(WARNING) << "Ignoring message sent for external extension '"
                 << extension_->name() << "' which doesn't support it.";
    return;
  }

  std::string string_msg;
  if (!msg->GetAsString(&string_msg)) {
    LOG(WARNING) << "Failed to retrieve the message's value.";
    return;
  }
  callback(xw_instance_, string_msg.c_str());
}

void XWalkExternalInstance::HandleSyncMessage(scoped_ptr<base::Value> msg) {
  XW_HandleSyncMessageCallback callback = extension_->handle_sync_msg_callback_;
  if (!callback) {
    LOG(WARNING) << "Ignoring sync message sent for external extension '"
                 << extension_->name() << "' which doesn't support it.";
    return;
  }

  std::string string_msg;
  if (!msg->GetAsString(&string_msg)) {
    LOG(WARNING) << "Failed to retrieve the sync message's value.";
    return;
  }

  callback(xw_instance_, string_msg.c_str());
}

void XWalkExternalInstance::CoreSetInstanceData(void* data) {
  instance_data_ = data;
}

void* XWalkExternalInstance::CoreGetInstanceData() {
  return instance_data_;
}

void XWalkExternalInstance::MessagingPostMessage(const char* msg) {
  PostMessageToJS(scoped_ptr<base::Value>(new base::StringValue(msg)));
}

void XWalkExternalInstance::SyncMessagingSetSyncReply(const char* reply) {
  SendSyncReplyToJS(scoped_ptr<base::Value>(new base::StringValue(reply)));
}

}  // namespace extensions
}  // namespace xwalk
<|endoftext|>