<commit_before>/*
 * yafdb - Yet Another Face Detection and Bluring
 *
 * Copyright (c) 2014 FOXEL SA - http://foxel.ch
 * Please read <http://foxel.ch/license> for more information.
 *
 *
 * Author(s):
 *
 *      Antony Ducommun <nitro@tmsrv.org>
 *      Kevin Velickovic <k.velickovic@foxel.ch>
 *
 *
 * This file is part of the FOXEL project <http://foxel.ch>.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Additional Terms:
 *
 *      You are required to preserve legal notices and author attributions in
 *      that material or in the Appropriate Legal Notices displayed by works
 *      containing it.
 *
 *      You are required to attribute the work as explained in the "Usage and
 *      Attribution" section of <http://foxel.ch/license>.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <math.h>

#include "detectors/detector.hpp"

/*
 * List of supported algorithms.
 *
 */

#define ALGORITHM_NONE         0
#define ALGORITHM_GAUSSIAN     1
#define ALGORITHM_PROGRESSIVE  2

/*
 * Program arguments.
 *
 */

#define OPTION_ALGORITHM              0
#define OPTION_MERGE_MIN_OVERLAP      1
#define OPTION_GAUSSIAN_KERNEL        2
#define OPTION_GAUSSIAN_STEPS         3
#define OPTION_RESIZE_WIDTH           4
#define OPTION_RESIZE_HEIGHT          5

static int resize_width = 0;
static int resize_height = 0;
static int algorithm = ALGORITHM_GAUSSIAN;
static int merge_min_overlap = 1;
static double gaussian_kernel_size = 65;
static double gaussian_steps = 1;
static const char *source_file = NULL;
static const char *objects_file = NULL;
static const char *target_file = NULL;

static struct option options[] = {
    {"algorithm",           required_argument, 0,                 'a'},
    {"merge-min-overlap",   required_argument, 0,                  0 },
    {"gaussian-kernel",     required_argument, 0,                  0 },
    {"gaussian-steps",      required_argument, 0,                  0 },
    {"resize-width",        required_argument, 0,                  0 },
    {"resize-height",       required_argument, 0,                  0 },
    {0, 0, 0, 0}
};

//! Progressive rectangular blurring

//! Apply a progresive blur on the desired rectangle.
//!
//! @param pbBitmap Bitmap array pointer to result image
//! @param pbSource Bitmap array pointer to source image
//! @param pbWidth Bitmap width, in pixels
//! @param pbHeight Bitmap height, in pixels
//! @param pbChannel Layer on which blur apply
//! @param pbRx1 Rectangle upper left corner x coordinates
//! @param pbRy1 Rectangle upper left corner y coordinates
//! @param pbRx2 Rectangle lower right corner x coordinates
//! @param pbRy2 Rectangle lower right corner y coordinates

void progblur ( unsigned char * pbBitmap, int pbWidth, int pbHeight, int pbChannel, int pbRx1, int pbRy1, int pbRx2, int pbRy2 ) {

    /* Parsing variables */
    int pbX = 0;
    int pbY = 0;
    int pbI = 0;
    int pbJ = 0;

    /* Function parameters */
    float pbU = 0.0;
    float pbV = 0.0;

    /* Area boudaries */
    int pbAX1 = 0;
    int pbAY1 = 0;
    int pbAX2 = 0;
    int pbAY2 = 0;

    /* Compute rectangle size */
    int pbrWidth  = ( pbRx2 - pbRx1 );
    int pbrHeight = ( pbRy2 - pbRy1 );

    /* Compute rectangle center */
    float pbCX = ( float ) pbrWidth  / 2.0 + pbRx1;
    float pbCY = ( float ) pbrHeight / 2.0 + pbRy1;

    /* Compute automatic factor */
    float pbFactor = pbrWidth < pbrHeight ? pbrWidth : pbrHeight;

    /* Chromaitc accumulator */
    float pbAccumR = 0.0;
    float pbAccumG = 0.0;
    float pbAccumB = 0.0;
    int   pbForce  = 0;
    int   pbCount  = 0;

    /* Optimization for bitmap offset */
    unsigned char * pbOffset = NULL;

    /* Optimization for bitmap sub-offset */
    int pbYOffset = 0;
    int pbJOffset = 0;

    /* Increase rectangle size */
    pbRx1 = pbCX - pbFactor;
    pbRx2 = pbCX + pbFactor;
    pbRy1 = pbCY - pbFactor;
    pbRy2 = pbCY + pbFactor;

    /* Recompute adapted width and height */
    pbrWidth  = ( pbRx2 - pbRx1 );
    pbrHeight = ( pbRy2 - pbRy1 );

    /* Optimization operation */
    pbFactor *= 0.2;

    /* Blurring y-component loop */
    for ( pbY = pbRy1; pbY <= pbRy2; pbY ++ ) {

        /* Compute optimization sub-offset */
        pbYOffset = pbChannel * pbWidth * pbY;

        /* Compute coordinates v-parameters */
        pbV = ( ( float ) ( pbY - pbRy1 ) / pbrHeight ) * 2.0 - 1.0;

        /* Blurring x-component loop */
        for ( pbX = pbRx1; pbX <= pbRx2; pbX ++ ) {

            /* Reset chromatic accumulator */
            pbAccumR = 0.0;
            pbAccumG = 0.0;
            pbAccumB = 0.0;

            /* Compute coordinates u-parameters */
            pbU = ( ( float ) ( pbX - pbRx1 ) / pbrWidth  ) * 2.0 - 1.0;

            /* Compute recursive condition value */
            pbForce = int( exp( - pbU * pbU * 3.5 ) * exp( - pbV * pbV * 3.5 ) * pbFactor );

            pbForce = ( pbForce > 32 ) ? 32 : pbForce;

            /* Create area boundaries */
            pbAX1 = pbX - pbForce; pbAX1 = ( pbAX1 <         0 ) ?            0 : pbAX1;
            pbAX2 = pbX + pbForce; pbAX2 = ( pbAX2 >=  pbWidth ) ? pbWidth  - 1 : pbAX2;
            pbAY1 = pbY - pbForce; pbAY1 = ( pbAY1 <         0 ) ?            0 : pbAY1;
            pbAY2 = pbY + pbForce; pbAY2 = ( pbAY2 >= pbHeight ) ? pbHeight - 1 : pbAY2;

            /* Accumulates y-components */
            for ( pbJ = pbAY1; pbJ <= pbAY2; pbJ ++ ) {

                /* Compute optimization sub-offset */
                pbJOffset = pbChannel * pbWidth * pbJ;

                /* Accumulates x-components */
                for ( pbI = pbAX1; pbI <= pbAX2; pbI ++ ) {

                    /* Compute optimiztion offset */
                    pbOffset = pbBitmap + pbJOffset + pbChannel * pbI;

                    /* Accumulate chromatic value */
                    pbAccumR += * ( pbOffset ++ );
                    pbAccumG += * ( pbOffset ++ );
                    pbAccumB += * ( pbOffset    );

                }

            }

            /* Compute number of considered pixels */
            pbCount = ( pbAX2 - pbAX1 + 1 ) * ( pbAY2 - pbAY1 + 1 );

            /* Compute optimization offset */
            pbOffset = pbBitmap + pbYOffset + pbChannel * pbX;

            /* Assign mean value */
            * ( pbOffset ++ ) = pbAccumR / pbCount;
            * ( pbOffset ++ ) = pbAccumG / pbCount;
            * ( pbOffset    ) = pbAccumB / pbCount;

        }

    }

}

/**
 * Display program usage.
 *
 */
void usage() {
    printf("yafdb-blur --algorithm algo input-image.tiff input-objects.yaml output-image.tiff\n\n");

    printf("Blurs detected objects and write modified image as output.\n\n");

    printf("General options:\n\n");
    printf("--algorithm algo : algorithm to use for blurring ('gaussian', 'progressive')\n");
    printf("--merge-min-overlap 1 : minimum occurrence of overlap to keep detected objects\n");
    printf("\n");

    printf("Gaussian options:\n\n");
    printf("--gaussian-kernel 65 : gaussian kernel size\n");
    printf("--gaussian-steps 1 : gaussian blurring steps\n");
    printf("\n");

    printf("Resizing options:\n\n");
    printf("--resize-width 800: Resizing width\n");
    printf("--resize-height 600: Resizing height\n");
    printf("\n");
}

/**
 * Program entry-point.
 *
 */
int main(int argc, char **argv) {
    // parse arguments
    while (true) {
        int index = -1;

        getopt_long(argc, argv, "", options, &index);
        if (index == -1) {
            if (argc != optind + 3) {
                usage();
                return 1;
            }

            source_file = argv[optind++];
            if (access(source_file, R_OK)) {
                fprintf(stderr, "Error: source file not readable: %s\n", source_file);
                return 2;
            }

            objects_file = argv[optind++];
            if (access(objects_file, R_OK)) {
                fprintf(stderr, "Error: detected objects file not readable: %s\n", objects_file);
                return 2;
            }

            target_file = argv[optind++];
            if (access(target_file, W_OK) && errno == EACCES) {
                fprintf(stderr, "Error: target file not writable: %s\n", target_file);
                return 2;
            }
            break;
        }

        switch (index) {
        case OPTION_ALGORITHM:
            if (strcmp(optarg, "none") == 0) {
                algorithm = ALGORITHM_NONE;
            } else if (strcmp(optarg, "gaussian") == 0) {
                algorithm = ALGORITHM_GAUSSIAN;
            } else if (strcmp(optarg, "progressive") == 0) {
                algorithm = ALGORITHM_PROGRESSIVE;
            } else {
                fprintf(stderr, "Error: unsupported algorithm: %s\n", optarg);
            }
            break;

        case OPTION_MERGE_MIN_OVERLAP:
            merge_min_overlap = atoi(optarg);
            break;

        case OPTION_GAUSSIAN_KERNEL:
            gaussian_kernel_size = atof(optarg);
            break;
        case OPTION_GAUSSIAN_STEPS:
            gaussian_steps = atof(optarg);
            break;
        case OPTION_RESIZE_WIDTH:
            resize_width = atoi(optarg);
            break;
        case OPTION_RESIZE_HEIGHT:
            resize_height = atoi(optarg);
            break;

        default:
            usage();
            return 1;
        }
    }

    // read source file
    cv::Mat source = cv::imread(source_file);

    if (source.rows <= 0 || source.cols <= 0) {
        fprintf(stderr, "Error: cannot read image in source file: %s\n", source_file);
        return 2;
    }

    // read detected objects
    std::list<DetectedObject> objects;

    if (!ObjectDetector::load(objects_file, objects)) {
        fprintf(stderr, "Error: cannot read objects in file: %s\n", objects_file);
        return 2;
    }

    // merge detected objects
    ObjectDetector::merge(objects, merge_min_overlap);

    // apply blur operation
    for (int i = 0; i < gaussian_steps; ++i)
    {
        std::for_each(objects.begin(), objects.end(), [&] (const DetectedObject &object) {
            auto rects = object.area.rects(source.cols, source.rows);

            std::for_each(rects.begin(), rects.end(), [&] (const cv::Rect &rect) {
                cv::Mat region(source, rect);

                switch (algorithm) {
                case ALGORITHM_NONE:
                    break;

                case ALGORITHM_GAUSSIAN:
                {
                    GaussianBlur(
                        region,
                        region,
                        cv::Size(gaussian_kernel_size, gaussian_kernel_size),
                        0,
                        0
                    );
                }
                break;

                case ALGORITHM_PROGRESSIVE:
                {
                    progblur (
                        source.data,
                        source.cols,
                        source.rows,
                        source.channels(),
                        rect.x,
                        rect.y,
                        rect.x + rect.width,
                        rect.y + rect.height
                    );
                }
                break;

                default:
                    fprintf(stderr, "Error: unsupported blur algorithm!\n");
                    break;
                }
            });
        });
    }

    // Configure the quality level for jpeg images
    std::vector<int> compression_params;
    compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
    compression_params.push_back(100);

    // Resize the image if specified
    if(resize_width > 0 && resize_height > 0)
    {
        // Create the resized image
        cv::Size size(resize_width, resize_height);
        cv::Mat resized_image;
        cv::resize(source, resized_image, size);

        // save target file
        cv::imwrite(target_file, resized_image, compression_params);
    } else {
        // save target file
        cv::imwrite(target_file, source, compression_params);
    }

    return 0;
}
<commit_msg>Fixed yafdb-blurr blurring invalidated objects.<commit_after>/*
 * yafdb - Yet Another Face Detection and Bluring
 *
 * Copyright (c) 2014 FOXEL SA - http://foxel.ch
 * Please read <http://foxel.ch/license> for more information.
 *
 *
 * Author(s):
 *
 *      Antony Ducommun <nitro@tmsrv.org>
 *      Kevin Velickovic <k.velickovic@foxel.ch>
 *
 *
 * This file is part of the FOXEL project <http://foxel.ch>.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Additional Terms:
 *
 *      You are required to preserve legal notices and author attributions in
 *      that material or in the Appropriate Legal Notices displayed by works
 *      containing it.
 *
 *      You are required to attribute the work as explained in the "Usage and
 *      Attribution" section of <http://foxel.ch/license>.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <math.h>

#include "detectors/detector.hpp"

/*
 * List of supported algorithms.
 *
 */

#define ALGORITHM_NONE         0
#define ALGORITHM_GAUSSIAN     1
#define ALGORITHM_PROGRESSIVE  2

/*
 * Program arguments.
 *
 */

#define OPTION_ALGORITHM              0
#define OPTION_MERGE_MIN_OVERLAP      1
#define OPTION_GAUSSIAN_KERNEL        2
#define OPTION_GAUSSIAN_STEPS         3
#define OPTION_RESIZE_WIDTH           4
#define OPTION_RESIZE_HEIGHT          5

static int resize_width = 0;
static int resize_height = 0;
static int algorithm = ALGORITHM_GAUSSIAN;
static int merge_min_overlap = 1;
static double gaussian_kernel_size = 65;
static double gaussian_steps = 1;
static const char *source_file = NULL;
static const char *objects_file = NULL;
static const char *target_file = NULL;

static struct option options[] = {
    {"algorithm",           required_argument, 0,                 'a'},
    {"merge-min-overlap",   required_argument, 0,                  0 },
    {"gaussian-kernel",     required_argument, 0,                  0 },
    {"gaussian-steps",      required_argument, 0,                  0 },
    {"resize-width",        required_argument, 0,                  0 },
    {"resize-height",       required_argument, 0,                  0 },
    {0, 0, 0, 0}
};

//! Progressive rectangular blurring

//! Apply a progresive blur on the desired rectangle.
//!
//! @param pbBitmap Bitmap array pointer to result image
//! @param pbSource Bitmap array pointer to source image
//! @param pbWidth Bitmap width, in pixels
//! @param pbHeight Bitmap height, in pixels
//! @param pbChannel Layer on which blur apply
//! @param pbRx1 Rectangle upper left corner x coordinates
//! @param pbRy1 Rectangle upper left corner y coordinates
//! @param pbRx2 Rectangle lower right corner x coordinates
//! @param pbRy2 Rectangle lower right corner y coordinates

void progblur ( unsigned char * pbBitmap, int pbWidth, int pbHeight, int pbChannel, int pbRx1, int pbRy1, int pbRx2, int pbRy2 ) {

    /* Parsing variables */
    int pbX = 0;
    int pbY = 0;
    int pbI = 0;
    int pbJ = 0;

    /* Function parameters */
    float pbU = 0.0;
    float pbV = 0.0;

    /* Area boudaries */
    int pbAX1 = 0;
    int pbAY1 = 0;
    int pbAX2 = 0;
    int pbAY2 = 0;

    /* Compute rectangle size */
    int pbrWidth  = ( pbRx2 - pbRx1 );
    int pbrHeight = ( pbRy2 - pbRy1 );

    /* Compute rectangle center */
    float pbCX = ( float ) pbrWidth  / 2.0 + pbRx1;
    float pbCY = ( float ) pbrHeight / 2.0 + pbRy1;

    /* Compute automatic factor */
    float pbFactor = pbrWidth < pbrHeight ? pbrWidth : pbrHeight;

    /* Chromaitc accumulator */
    float pbAccumR = 0.0;
    float pbAccumG = 0.0;
    float pbAccumB = 0.0;
    int   pbForce  = 0;
    int   pbCount  = 0;

    /* Optimization for bitmap offset */
    unsigned char * pbOffset = NULL;

    /* Optimization for bitmap sub-offset */
    int pbYOffset = 0;
    int pbJOffset = 0;

    /* Increase rectangle size */
    pbRx1 = pbCX - pbFactor;
    pbRx2 = pbCX + pbFactor;
    pbRy1 = pbCY - pbFactor;
    pbRy2 = pbCY + pbFactor;

    /* Recompute adapted width and height */
    pbrWidth  = ( pbRx2 - pbRx1 );
    pbrHeight = ( pbRy2 - pbRy1 );

    /* Optimization operation */
    pbFactor *= 0.2;

    /* Blurring y-component loop */
    for ( pbY = pbRy1; pbY <= pbRy2; pbY ++ ) {

        /* Compute optimization sub-offset */
        pbYOffset = pbChannel * pbWidth * pbY;

        /* Compute coordinates v-parameters */
        pbV = ( ( float ) ( pbY - pbRy1 ) / pbrHeight ) * 2.0 - 1.0;

        /* Blurring x-component loop */
        for ( pbX = pbRx1; pbX <= pbRx2; pbX ++ ) {

            /* Reset chromatic accumulator */
            pbAccumR = 0.0;
            pbAccumG = 0.0;
            pbAccumB = 0.0;

            /* Compute coordinates u-parameters */
            pbU = ( ( float ) ( pbX - pbRx1 ) / pbrWidth  ) * 2.0 - 1.0;

            /* Compute recursive condition value */
            pbForce = int( exp( - pbU * pbU * 3.5 ) * exp( - pbV * pbV * 3.5 ) * pbFactor );

            pbForce = ( pbForce > 32 ) ? 32 : pbForce;

            /* Create area boundaries */
            pbAX1 = pbX - pbForce; pbAX1 = ( pbAX1 <         0 ) ?            0 : pbAX1;
            pbAX2 = pbX + pbForce; pbAX2 = ( pbAX2 >=  pbWidth ) ? pbWidth  - 1 : pbAX2;
            pbAY1 = pbY - pbForce; pbAY1 = ( pbAY1 <         0 ) ?            0 : pbAY1;
            pbAY2 = pbY + pbForce; pbAY2 = ( pbAY2 >= pbHeight ) ? pbHeight - 1 : pbAY2;

            /* Accumulates y-components */
            for ( pbJ = pbAY1; pbJ <= pbAY2; pbJ ++ ) {

                /* Compute optimization sub-offset */
                pbJOffset = pbChannel * pbWidth * pbJ;

                /* Accumulates x-components */
                for ( pbI = pbAX1; pbI <= pbAX2; pbI ++ ) {

                    /* Compute optimiztion offset */
                    pbOffset = pbBitmap + pbJOffset + pbChannel * pbI;

                    /* Accumulate chromatic value */
                    pbAccumR += * ( pbOffset ++ );
                    pbAccumG += * ( pbOffset ++ );
                    pbAccumB += * ( pbOffset    );

                }

            }

            /* Compute number of considered pixels */
            pbCount = ( pbAX2 - pbAX1 + 1 ) * ( pbAY2 - pbAY1 + 1 );

            /* Compute optimization offset */
            pbOffset = pbBitmap + pbYOffset + pbChannel * pbX;

            /* Assign mean value */
            * ( pbOffset ++ ) = pbAccumR / pbCount;
            * ( pbOffset ++ ) = pbAccumG / pbCount;
            * ( pbOffset    ) = pbAccumB / pbCount;

        }

    }

}

/**
 * Display program usage.
 *
 */
void usage() {
    printf("yafdb-blur --algorithm algo input-image.tiff input-objects.yaml output-image.tiff\n\n");

    printf("Blurs detected objects and write modified image as output.\n\n");

    printf("General options:\n\n");
    printf("--algorithm algo : algorithm to use for blurring ('gaussian', 'progressive')\n");
    printf("--merge-min-overlap 1 : minimum occurrence of overlap to keep detected objects\n");
    printf("\n");

    printf("Gaussian options:\n\n");
    printf("--gaussian-kernel 65 : gaussian kernel size\n");
    printf("--gaussian-steps 1 : gaussian blurring steps\n");
    printf("\n");

    printf("Resizing options:\n\n");
    printf("--resize-width 800: Resizing width\n");
    printf("--resize-height 600: Resizing height\n");
    printf("\n");
}

/**
 * Program entry-point.
 *
 */
int main(int argc, char **argv) {
    // parse arguments
    while (true) {
        int index = -1;

        getopt_long(argc, argv, "", options, &index);
        if (index == -1) {
            if (argc != optind + 3) {
                usage();
                return 1;
            }

            source_file = argv[optind++];
            if (access(source_file, R_OK)) {
                fprintf(stderr, "Error: source file not readable: %s\n", source_file);
                return 2;
            }

            objects_file = argv[optind++];
            if (access(objects_file, R_OK)) {
                fprintf(stderr, "Error: detected objects file not readable: %s\n", objects_file);
                return 2;
            }

            target_file = argv[optind++];
            if (access(target_file, W_OK) && errno == EACCES) {
                fprintf(stderr, "Error: target file not writable: %s\n", target_file);
                return 2;
            }
            break;
        }

        switch (index) {
        case OPTION_ALGORITHM:
            if (strcmp(optarg, "none") == 0) {
                algorithm = ALGORITHM_NONE;
            } else if (strcmp(optarg, "gaussian") == 0) {
                algorithm = ALGORITHM_GAUSSIAN;
            } else if (strcmp(optarg, "progressive") == 0) {
                algorithm = ALGORITHM_PROGRESSIVE;
            } else {
                fprintf(stderr, "Error: unsupported algorithm: %s\n", optarg);
            }
            break;

        case OPTION_MERGE_MIN_OVERLAP:
            merge_min_overlap = atoi(optarg);
            break;

        case OPTION_GAUSSIAN_KERNEL:
            gaussian_kernel_size = atof(optarg);
            break;
        case OPTION_GAUSSIAN_STEPS:
            gaussian_steps = atof(optarg);
            break;
        case OPTION_RESIZE_WIDTH:
            resize_width = atoi(optarg);
            break;
        case OPTION_RESIZE_HEIGHT:
            resize_height = atoi(optarg);
            break;

        default:
            usage();
            return 1;
        }
    }

    // read source file
    cv::Mat source = cv::imread(source_file);

    if (source.rows <= 0 || source.cols <= 0) {
        fprintf(stderr, "Error: cannot read image in source file: %s\n", source_file);
        return 2;
    }

    // read detected objects
    std::list<DetectedObject> objects;

    if (!ObjectDetector::load(objects_file, objects)) {
        fprintf(stderr, "Error: cannot read objects in file: %s\n", objects_file);
        return 2;
    }

    // merge detected objects
    ObjectDetector::merge(objects, merge_min_overlap);

    // apply blur operation
    for (int i = 0; i < gaussian_steps; ++i)
    {
        std::for_each(objects.begin(), objects.end(), [&] (const DetectedObject &object) {
            if(object.falsePositive != "Yes")
            {
                auto rects = object.area.rects(source.cols, source.rows);

                std::for_each(rects.begin(), rects.end(), [&] (const cv::Rect &rect) {
                    cv::Mat region(source, rect);

                    switch (algorithm) {
                    case ALGORITHM_NONE:
                        break;

                    case ALGORITHM_GAUSSIAN:
                    {
                        GaussianBlur(
                            region,
                            region,
                            cv::Size(gaussian_kernel_size, gaussian_kernel_size),
                            0,
                            0
                        );
                    }
                    break;

                    case ALGORITHM_PROGRESSIVE:
                    {
                        progblur (
                            source.data,
                            source.cols,
                            source.rows,
                            source.channels(),
                            rect.x,
                            rect.y,
                            rect.x + rect.width,
                            rect.y + rect.height
                        );
                    }
                    break;

                    default:
                        fprintf(stderr, "Error: unsupported blur algorithm!\n");
                        break;
                    }
                });
            }
        });
    }

    // Configure the quality level for jpeg images
    std::vector<int> compression_params;
    compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
    compression_params.push_back(100);

    // Resize the image if specified
    if(resize_width > 0 && resize_height > 0)
    {
        // Create the resized image
        cv::Size size(resize_width, resize_height);
        cv::Mat resized_image;
        cv::resize(source, resized_image, size);

        // save target file
        cv::imwrite(target_file, resized_image, compression_params);
    } else {
        // save target file
        cv::imwrite(target_file, source, compression_params);
    }

    return 0;
}
<|endoftext|>


<commit_before>
#include <girepository.h>
#include <glib.h>

#include "boxed.h"
#include "debug.h"
#include "function.h"
#include "gi.h"
#include "gobject.h"
#include "type.h"
#include "util.h"
#include "value.h"

using v8::Array;
using v8::External;
using v8::Function;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Persistent;
using Nan::New;
using Nan::WeakCallbackType;

namespace GNodeJS {

size_t Boxed::GetSize (GIBaseInfo *boxed_info) {
    GIInfoType i_type = g_base_info_get_type(boxed_info);
    if (i_type == GI_INFO_TYPE_STRUCT) {
        return g_struct_info_get_size((GIStructInfo*)boxed_info);
    } else if (i_type == GI_INFO_TYPE_UNION) {
        return g_union_info_get_size((GIUnionInfo*)boxed_info);
    } else {
        g_assert_not_reached();
    }
}

static bool IsNoArgsConstructor(GIFunctionInfo *info) {
    auto flags = g_function_info_get_flags (info);
    return ((flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0
        && g_callable_info_get_n_args (info) == 0);
}

static GIFunctionInfo* FindBoxedConstructor(GIBaseInfo* info) {
    if (GI_IS_STRUCT_INFO (info)) {
        int n_methods = g_struct_info_get_n_methods (info);
        for (int i = 0; i < n_methods; i++) {
            GIFunctionInfo* fn_info = g_struct_info_get_method (info, i);
            if (IsNoArgsConstructor (fn_info))
                return fn_info;
            g_base_info_unref(fn_info);
        }
    }
    else {
        int n_methods = g_union_info_get_n_methods (info);
        for (int i = 0; i < n_methods; i++) {
            GIFunctionInfo* fn_info = g_union_info_get_method (info, i);
            if (IsNoArgsConstructor (fn_info))
                return fn_info;
            g_base_info_unref(fn_info);
        }
    }
    return NULL;
}

static void BoxedDestroyed(const Nan::WeakCallbackInfo<Boxed> &info);

static void BoxedConstructor(const Nan::FunctionCallbackInfo<Value> &info) {
    /* See gobject.cc for how this works */
    if (!info.IsConstructCall ()) {
        Nan::ThrowTypeError("Not a construct call");
        return;
    }

    void *boxed = NULL;
    unsigned long size = 0;

    Local<Object> self = info.This ();
    GIBaseInfo *gi_info = (GIBaseInfo *) External::Cast (*info.Data ())->Value ();
    GType gtype = g_registered_type_info_get_g_type (gi_info);

    if (info[0]->IsExternal ()) {
        /* The External case. This is how WrapperFromBoxed is called. */

        boxed = External::Cast(*info[0])->Value();

    } else {
        /* User code calling `new Pango.AttrList()` */

        size = Boxed::GetSize(gi_info);

        if (size != 0) {
            boxed = g_slice_alloc0(size);
        }
        /* TODO(find what to do in these cases)
        else {
            GIFunctionInfo* fn_info = FindBoxedConstructor(gi_info);

            if (fn_info != NULL) {
                GError *error = NULL;
                GIArgument return_value;
                g_function_info_invoke (fn_info,
                        NULL, 0, NULL, 0, &return_value, &error);
                g_base_info_unref(fn_info);

                if (error != NULL) {
                    Util::ThrowGError("Boxed allocation failed", error);
                    return;
                }

                boxed = return_value.v_pointer;
            }
        } */

        if (!boxed) {
            Nan::ThrowError("Boxed allocation failed");
            return;
        }
    }

    self->SetAlignedPointerInInternalField (0, boxed);

    Nan::DefineOwnProperty(self,
            UTF8("__gtype__"),
            Nan::New<Number>(gtype),
            (v8::PropertyAttribute)(v8::PropertyAttribute::ReadOnly | v8::PropertyAttribute::DontEnum)
    );

    auto* box = new Boxed();
    box->data = boxed;
    box->size = size;
    box->g_type = gtype;
    box->persistent = new Nan::Persistent<Object>(self);
    box->persistent->SetWeak(box, BoxedDestroyed, Nan::WeakCallbackType::kParameter);
}

static void BoxedDestroyed(const Nan::WeakCallbackInfo<Boxed> &info) {
    Boxed *box = info.GetParameter();

    if (G_TYPE_IS_BOXED(box->g_type)) {
        g_boxed_free(box->g_type, box->data);
    }
    else if (box->size != 0) {
        // Allocated in ./function.cc @ AllocateArgument
        g_slice_free1(box->size, box->data);
    }
    else if (box->data != NULL) {
        /*
         * TODO(find informations on what to do here. Only seems to be reached for GI.Typelib)
         */
        log("boxed possibly not freed");
    }

    delete box->persistent;
    delete box;
}

Local<FunctionTemplate> GetBoxedTemplate(GIBaseInfo *info, GType gtype) {
    void *data = NULL;

    if (gtype != G_TYPE_NONE) {
        data = g_type_get_qdata(gtype, GNodeJS::template_quark());
    }

    /*
     * Template already created
     */

    if (data) {
        Persistent<FunctionTemplate> *persistent = (Persistent<FunctionTemplate> *) data;
        Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate> (*persistent);
        return tpl;
    }

    /*
     * Template not created yet
     */

    auto tpl = New<FunctionTemplate>(BoxedConstructor, New<External>(info));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    if (gtype != G_TYPE_NONE) {
        const char *class_name = g_type_name(gtype);
        tpl->SetClassName (UTF8(class_name));
    } else {
        const char *class_name = g_base_info_get_name (info);
        tpl->SetClassName (UTF8(class_name));
    }

    if (gtype == G_TYPE_NONE)
        return tpl;

    Isolate *isolate = Isolate::GetCurrent();
    auto *persistent = new v8::Persistent<FunctionTemplate>(isolate, tpl);
    persistent->SetWeak(
            g_base_info_ref(info),
            GNodeJS::ClassDestroyed,
            WeakCallbackType::kParameter);

    g_type_set_qdata(gtype, GNodeJS::template_quark(), persistent);

    return tpl;
}

Local<Function> MakeBoxedClass(GIBaseInfo *info) {
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);

    if (gtype == G_TYPE_NONE) {
        auto moduleCache = GNodeJS::GetModuleCache();
        auto ns   = UTF8 (g_base_info_get_namespace (info));
        auto name = UTF8 (g_base_info_get_name (info));

        if (Nan::HasOwnProperty(moduleCache, ns).FromMaybe(false)) {
            auto module = Nan::Get(moduleCache, ns).ToLocalChecked()->ToObject();

            if (Nan::HasOwnProperty(module, name).FromMaybe(false)) {
                auto constructor = Nan::Get(module, name).ToLocalChecked()->ToObject();
                return Local<Function>::Cast (constructor);
            }
        }
    }

    Local<FunctionTemplate> tpl = GetBoxedTemplate (info, gtype);
    return tpl->GetFunction ();
}

Local<Value> WrapperFromBoxed(GIBaseInfo *info, void *data) {
    if (data == NULL)
        return Nan::Null();

    Local<Function> constructor = MakeBoxedClass (info);

    Local<Value> boxed_external = Nan::New<External> (data);
    Local<Value> args[] = { boxed_external };
    // FIXME(we're not handling failure here)
    MaybeLocal<Object> instance = Nan::NewInstance(constructor, 1, args);
    return instance.ToLocalChecked();
}

void* BoxedFromWrapper(Local<Value> value) {
    Local<Object> object = value->ToObject ();
    g_assert(object->InternalFieldCount() > 0);
    void *boxed = object->GetAlignedPointerFromInternalField(0);
    return boxed;
}

};
<commit_msg>boxed: use "new" method as constructor if available<commit_after>
#include <girepository.h>
#include <glib.h>

#include "boxed.h"
#include "debug.h"
#include "function.h"
#include "gi.h"
#include "gobject.h"
#include "type.h"
#include "util.h"
#include "value.h"

using v8::Array;
using v8::External;
using v8::Function;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Persistent;
using Nan::New;
using Nan::WeakCallbackType;

namespace GNodeJS {

size_t Boxed::GetSize (GIBaseInfo *boxed_info) {
    GIInfoType i_type = g_base_info_get_type(boxed_info);
    if (i_type == GI_INFO_TYPE_STRUCT) {
        return g_struct_info_get_size((GIStructInfo*)boxed_info);
    } else if (i_type == GI_INFO_TYPE_UNION) {
        return g_union_info_get_size((GIUnionInfo*)boxed_info);
    } else {
        g_assert_not_reached();
    }
}

static bool IsNoArgsConstructor(GIFunctionInfo *info) {
    auto flags = g_function_info_get_flags (info);
    return ((flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0
        && g_callable_info_get_n_args (info) == 0);
}

static GIFunctionInfo* FindBoxedConstructor(GIBaseInfo* info) {
    if (GI_IS_STRUCT_INFO (info)) {
        int n_methods = g_struct_info_get_n_methods (info);
        for (int i = 0; i < n_methods; i++) {
            GIFunctionInfo* fn_info = g_struct_info_get_method (info, i);
            if (IsNoArgsConstructor (fn_info))
                return fn_info;
            g_base_info_unref(fn_info);
        }

        return g_struct_info_find_method(info, "new");
    }
    else {
        int n_methods = g_union_info_get_n_methods (info);
        for (int i = 0; i < n_methods; i++) {
            GIFunctionInfo* fn_info = g_union_info_get_method (info, i);
            if (IsNoArgsConstructor (fn_info))
                return fn_info;
            g_base_info_unref(fn_info);
        }

        return g_union_info_find_method(info, "new");
    }
}

static void BoxedDestroyed(const Nan::WeakCallbackInfo<Boxed> &info);

static void BoxedConstructor(const Nan::FunctionCallbackInfo<Value> &info) {
    /* See gobject.cc for how this works */
    if (!info.IsConstructCall ()) {
        Nan::ThrowTypeError("Not a construct call");
        return;
    }

    void *boxed = NULL;
    unsigned long size = 0;

    Local<Object> self = info.This ();
    GIBaseInfo *gi_info = (GIBaseInfo *) External::Cast (*info.Data ())->Value ();
    GType gtype = g_registered_type_info_get_g_type (gi_info);

    if (info[0]->IsExternal ()) {
        /* The External case. This is how WrapperFromBoxed is called. */

        boxed = External::Cast(*info[0])->Value();

    } else {
        /* User code calling `new Pango.AttrList()` */

        size = Boxed::GetSize(gi_info);

        if (size != 0) {
            boxed = g_slice_alloc0(size);
        }
        // TODO(find what to do in these cases)
        /* else {
            GIFunctionInfo* fn_info = FindBoxedConstructor(gi_info);

            if (fn_info != NULL) {

                auto value = CallFunctionInfo (fn_info, info);

                if (value.IsEmpty())
                    return; // did throw

                GIArgument arg;

                if (V8ToGIArgument(gi_info, &arg, value))
                    boxed = arg.v_pointer;
                else
                    return; // did throw

            } else {
                log("constructor not found");
            }
        } */

        if (!boxed) {
            Nan::ThrowError("Boxed allocation failed");
            return;
        }
    }

    self->SetAlignedPointerInInternalField (0, boxed);

    Nan::DefineOwnProperty(self,
            UTF8("__gtype__"),
            Nan::New<Number>(gtype),
            (v8::PropertyAttribute)(v8::PropertyAttribute::ReadOnly | v8::PropertyAttribute::DontEnum)
    );

    auto* box = new Boxed();
    box->data = boxed;
    box->size = size;
    box->g_type = gtype;
    box->persistent = new Nan::Persistent<Object>(self);
    box->persistent->SetWeak(box, BoxedDestroyed, Nan::WeakCallbackType::kParameter);
}

static void BoxedDestroyed(const Nan::WeakCallbackInfo<Boxed> &info) {
    Boxed *box = info.GetParameter();

    if (G_TYPE_IS_BOXED(box->g_type)) {
        g_boxed_free(box->g_type, box->data);
    }
    else if (box->size != 0) {
        // Allocated in ./function.cc @ AllocateArgument
        g_slice_free1(box->size, box->data);
    }
    else if (box->data != NULL) {
        /*
         * TODO(find informations on what to do here. Only seems to be reached for GI.Typelib)
         */
        log("boxed possibly not freed");
    }

    delete box->persistent;
    delete box;
}

Local<FunctionTemplate> GetBoxedTemplate(GIBaseInfo *info, GType gtype) {
    void *data = NULL;

    if (gtype != G_TYPE_NONE) {
        data = g_type_get_qdata(gtype, GNodeJS::template_quark());
    }

    /*
     * Template already created
     */

    if (data) {
        Persistent<FunctionTemplate> *persistent = (Persistent<FunctionTemplate> *) data;
        Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate> (*persistent);
        return tpl;
    }

    /*
     * Template not created yet
     */

    auto tpl = New<FunctionTemplate>(BoxedConstructor, New<External>(info));
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    if (gtype != G_TYPE_NONE) {
        const char *class_name = g_type_name(gtype);
        tpl->SetClassName (UTF8(class_name));
    } else {
        const char *class_name = g_base_info_get_name (info);
        tpl->SetClassName (UTF8(class_name));
    }

    if (gtype == G_TYPE_NONE)
        return tpl;

    Isolate *isolate = Isolate::GetCurrent();
    auto *persistent = new v8::Persistent<FunctionTemplate>(isolate, tpl);
    persistent->SetWeak(
            g_base_info_ref(info),
            GNodeJS::ClassDestroyed,
            WeakCallbackType::kParameter);

    g_type_set_qdata(gtype, GNodeJS::template_quark(), persistent);

    return tpl;
}

Local<Function> MakeBoxedClass(GIBaseInfo *info) {
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);

    if (gtype == G_TYPE_NONE) {
        auto moduleCache = GNodeJS::GetModuleCache();
        auto ns   = UTF8 (g_base_info_get_namespace (info));
        auto name = UTF8 (g_base_info_get_name (info));

        if (Nan::HasOwnProperty(moduleCache, ns).FromMaybe(false)) {
            auto module = Nan::Get(moduleCache, ns).ToLocalChecked()->ToObject();

            if (Nan::HasOwnProperty(module, name).FromMaybe(false)) {
                auto constructor = Nan::Get(module, name).ToLocalChecked()->ToObject();
                return Local<Function>::Cast (constructor);
            }
        }
    }

    Local<FunctionTemplate> tpl = GetBoxedTemplate (info, gtype);
    return tpl->GetFunction ();
}

Local<Value> WrapperFromBoxed(GIBaseInfo *info, void *data) {
    if (data == NULL)
        return Nan::Null();

    Local<Function> constructor = MakeBoxedClass (info);

    Local<Value> boxed_external = Nan::New<External> (data);
    Local<Value> args[] = { boxed_external };
    // FIXME(we're not handling failure here)
    MaybeLocal<Object> instance = Nan::NewInstance(constructor, 1, args);
    return instance.ToLocalChecked();
}

void* BoxedFromWrapper(Local<Value> value) {
    Local<Object> object = value->ToObject ();
    g_assert(object->InternalFieldCount() > 0);
    void *boxed = object->GetAlignedPointerFromInternalField(0);
    return boxed;
}

};
<|endoftext|>


<commit_before>#include "game.hpp"

bool Game::uciHandler(std::string str) {
	std::vector<std::string> cmd = getStringArray(str);
		if(cmd[0] == "isready") {
			std::cout << "readyok" << std::endl;
		} else if(cmd[0] == "position") {
			gameHash.clear();
			gameHash.resize(0);
			hash_decrement = 0;
			if(cmd[1] == "startpos") {
				game_board.setFen(game_board.startpos_fen);
				hash_decrement = 0;
				hashAge = 0;
				if(cmd.size() > 3) {
					if(cmd[2] == "moves") {
						for(unsigned int i = 3; i < cmd.size(); ++i) {
							move(cmd[i]);
						}
					}
				}
			} else if(cmd[1] == "fen") {
				std::string fen;
				unsigned int pos = 2;

				for(unsigned int i = 2; i < 8; ++i) {
					fen += cmd[i];
					if(i != cmd.size() - 1) {
						fen.push_back(' ');
					}
					++pos;
				}

				game_board.setFen(fen);
				if(cmd.size() > pos) {
					if(cmd[pos] == "moves") {
						for(unsigned int i = pos + 1; i < cmd.size(); ++i) {
							move(cmd[i]);
						}
					}
				}
			}
		} else if(cmd[0] == "go") {
			if(cmd[1] == "depth") {
				max_depth = std::stoi(cmd[2]);
			  goFixedDepth();
			} else if(cmd[1] == "movetime") {
				goFixedTime(std::stoll(cmd[2]), false);
			} else if(cmd[1] == "infinite") {
				max_depth = 99;
				goFixedDepth();
			} else {
				wtime = 0, btime = 0;
				winc = 0, binc = 0, movestogo = 0, movestogoEnable = false;
				for(unsigned int i = 1; i < cmd.size(); ++i) {
					if(cmd[i] == "wtime") {
						wtime = std::stoll(cmd[i + 1]);
					} else if(cmd[i] == "btime") {
						btime = std::stoll(cmd[i + 1]);
					} else if(cmd[i] == "winc") {
						winc = std::stoll(cmd[i + 1]);
					} else if(cmd[i] == "binc") {
						binc = std::stoll(cmd[i + 1]);
					} else if(cmd[i] == "movestogo") {
						movestogoEnable = true;
						movestogo = std::stoi(cmd[i+1]);
					}
				}

				goTournament();
			}
		} else if(cmd[0] == "posmoves") {
			MoveArray moves;
			game_board.bitBoardMoveGenerator(moves, stress);

			for(unsigned int i = 0; i < moves.count; ++i) {
				std::cout << moves.moveArray[i].getMoveString();
				std::cout << std::endl;
			}

			std::cout << game_board.getEvaluate() / PAWN_EV.mg * 100 << std::endl;
			std::cout << game_board.getFen() << std::endl;

			std::cout << "inCheck (WHITE) : " << game_board.inCheck(WHITE) << std::endl;
			std::cout << "inCheck (BLACK) : " << game_board.inCheck(BLACK) << std::endl;
			std::cout << "color_hash: " << game_board.getColorHash() << std::endl;
		} else if(cmd[0] == "move") {
			move(cmd[1]);
		} else if(cmd[0] == "quit") {
			return false;
		} else if(cmd[0] == "uci") {
			idPrint();
			option.print();
			std::cout << "uciok" << std::endl;
		} else if(cmd[0] == "bench") {
			std::cout << "Benchmarking (15 sec)..." << std::endl;
			game_board.stress = 0;
			double st = clock();
			while((clock() - st) / CLOCKS_PER_SEC < 15) {
				for(unsigned int i = 0; i < 10000000; ++i) {
					game_board.bitBoardMoveGenerator(moveArray[0], game_board.stress);
				}
			}
			std::cout << (int64_t)(game_board.stress / ((clock() - st) / CLOCKS_PER_SEC)) / 10000 << " scores" << std::endl;
		} else if(cmd[0] == "goback") {
			game_board.goBack();
			--hash_decrement;
		} else if(cmd[0] == "perft") {
			int k;
			k = std::stoi(cmd[1]);
			for(int i = 1; i <= k; ++i) {
				combinations = 0;
				double st = clock();
				uint64_t count = perft(i);
				std::cout << "Depth: " << i << "; count: " << combinations;
				std::cout << "; speed: " << (int64_t)((double)count / (((double)clock() - (double)st) / (double)CLOCKS_PER_SEC)) << std::endl;
			}
		} else if(cmd[0] == "setoption" && cmd[1] == "name") {
			if(cmd[2] == "Clear" && cmd[3] == "Hash") {
				clearCash();
				std::cout << "info hashfull 0" << std::endl;
			} else if(cmd[2] == "Hash" && cmd[3] == "value") {
				int hash_size = std::stoi(cmd[4]);

				hash_size = std::min(hash_size, option.max_hash_size);
				hash_size = std::max(hash_size, option.min_hash_size);

				setHashSize(hash_size);
			}  else if(cmd[2] == "Move" && cmd[3] == "Overhead" && cmd[4] == "value") {
				option.moveOverhead = std::stoi(cmd[5]);
				option.moveOverhead = std::min(option.moveOverhead, option.maxMoveOverhead);
				option.moveOverhead = std::max(option.moveOverhead, option.minMoveOverhead);
			} else if(cmd[2] == "UCI_AnalyseMode" && cmd[3] == "value") {
				if(cmd[4] == "true") {
					option.UCI_AnalyseMode = true;
				} else if(cmd[4] == "false") {
					option.UCI_AnalyseMode = false;
				}
			}
		}

		return true;
}

void Game::idPrint() {
	std::cout << "id name Zevra v1.8.2 r612" << std::endl;
	std::cout << "id author Oleg Smirnov @sovaz1997" << std::endl;
}<commit_msg>32.44 +/- 13.98 elo 10+0.1 (while not in infinite mode)<commit_after>#include "game.hpp"

bool Game::uciHandler(std::string str) {
	std::vector<std::string> cmd = getStringArray(str);
		if(cmd[0] == "isready") {
			std::cout << "readyok" << std::endl;
		} else if(cmd[0] == "position") {
			gameHash.clear();
			gameHash.resize(0);
			hash_decrement = 0;
			if(cmd[1] == "startpos") {
				game_board.setFen(game_board.startpos_fen);
				hash_decrement = 0;
				hashAge = 0;
				if(cmd.size() > 3) {
					if(cmd[2] == "moves") {
						for(unsigned int i = 3; i < cmd.size(); ++i) {
							move(cmd[i]);
						}
					}
				}
			} else if(cmd[1] == "fen") {
				std::string fen;
				unsigned int pos = 2;

				for(unsigned int i = 2; i < 8; ++i) {
					fen += cmd[i];
					if(i != cmd.size() - 1) {
						fen.push_back(' ');
					}
					++pos;
				}

				game_board.setFen(fen);
				if(cmd.size() > pos) {
					if(cmd[pos] == "moves") {
						for(unsigned int i = pos + 1; i < cmd.size(); ++i) {
							move(cmd[i]);
						}
					}
				}
			}
		} else if(cmd[0] == "go") {
			if(cmd[1] == "depth") {
				max_depth = std::stoi(cmd[2]);
			  goFixedDepth();
			} else if(cmd[1] == "movetime") {
				goFixedTime(std::stoll(cmd[2]), false);
			} else if(cmd[1] == "infinite") {
				max_depth = 99;
				goFixedDepth();
			} else {
				wtime = 0, btime = 0;
				winc = 0, binc = 0, movestogo = 0, movestogoEnable = false;
				for(unsigned int i = 1; i < cmd.size(); ++i) {
					if(cmd[i] == "wtime") {
						wtime = std::stoll(cmd[i + 1]);
					} else if(cmd[i] == "btime") {
						btime = std::stoll(cmd[i + 1]);
					} else if(cmd[i] == "winc") {
						winc = std::stoll(cmd[i + 1]);
					} else if(cmd[i] == "binc") {
						binc = std::stoll(cmd[i + 1]);
					} else if(cmd[i] == "movestogo") {
						movestogoEnable = true;
						movestogo = std::stoi(cmd[i+1]);
					}
				}

				goTournament();
			}
		} else if(cmd[0] == "posmoves") {
			MoveArray moves;
			game_board.bitBoardMoveGenerator(moves, stress);

			for(unsigned int i = 0; i < moves.count; ++i) {
				std::cout << moves.moveArray[i].getMoveString();
				std::cout << std::endl;
			}

			std::cout << game_board.getEvaluate() / PAWN_EV.mg * 100 << std::endl;
			std::cout << game_board.getFen() << std::endl;

			std::cout << "inCheck (WHITE) : " << game_board.inCheck(WHITE) << std::endl;
			std::cout << "inCheck (BLACK) : " << game_board.inCheck(BLACK) << std::endl;
			std::cout << "color_hash: " << game_board.getColorHash() << std::endl;
		} else if(cmd[0] == "move") {
			move(cmd[1]);
		} else if(cmd[0] == "quit") {
			return false;
		} else if(cmd[0] == "uci") {
			idPrint();
			option.print();
			std::cout << "uciok" << std::endl;
		} else if(cmd[0] == "bench") {
			std::cout << "Benchmarking (15 sec)..." << std::endl;
			game_board.stress = 0;
			double st = clock();
			while((clock() - st) / CLOCKS_PER_SEC < 15) {
				for(unsigned int i = 0; i < 10000000; ++i) {
					game_board.bitBoardMoveGenerator(moveArray[0], game_board.stress);
				}
			}
			std::cout << (int64_t)(game_board.stress / ((clock() - st) / CLOCKS_PER_SEC)) / 10000 << " scores" << std::endl;
		} else if(cmd[0] == "goback") {
			game_board.goBack();
			--hash_decrement;
		} else if(cmd[0] == "perft") {
			int k;
			k = std::stoi(cmd[1]);
			for(int i = 1; i <= k; ++i) {
				combinations = 0;
				double st = clock();
				uint64_t count = perft(i);
				std::cout << "Depth: " << i << "; count: " << combinations;
				std::cout << "; speed: " << (int64_t)((double)count / (((double)clock() - (double)st) / (double)CLOCKS_PER_SEC)) << std::endl;
			}
		} else if(cmd[0] == "setoption" && cmd[1] == "name") {
			if(cmd[2] == "Clear" && cmd[3] == "Hash") {
				clearCash();
				std::cout << "info hashfull 0" << std::endl;
			} else if(cmd[2] == "Hash" && cmd[3] == "value") {
				int hash_size = std::stoi(cmd[4]);

				hash_size = std::min(hash_size, option.max_hash_size);
				hash_size = std::max(hash_size, option.min_hash_size);

				setHashSize(hash_size);
			}  else if(cmd[2] == "Move" && cmd[3] == "Overhead" && cmd[4] == "value") {
				option.moveOverhead = std::stoi(cmd[5]);
				option.moveOverhead = std::min(option.moveOverhead, option.maxMoveOverhead);
				option.moveOverhead = std::max(option.moveOverhead, option.minMoveOverhead);
			} else if(cmd[2] == "UCI_AnalyseMode" && cmd[3] == "value") {
				if(cmd[4] == "true") {
					option.UCI_AnalyseMode = true;
				} else if(cmd[4] == "false") {
					option.UCI_AnalyseMode = false;
				}
			}
		}

		return true;
}

void Game::idPrint() {
	std::cout << "id name Zevra 180306" << std::endl;
	std::cout << "id author Oleg Smirnov @sovaz1997" << std::endl;
}<|endoftext|>


<commit_before>/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/*
 * Copyright (c) 2008  litl, LLC
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <config.h>

#include "ns.h"
#include "repo.h"
#include "param.h"
#include <gwkjs/gwkjs-module.h>
#include <gwkjs/compat.h>

#include <util/log.h>
#include <girepository.h>

#include <string.h>

typedef struct {
    char *gi_namespace;
    GHashTable *modules;
} Ns;

extern JSClassDefinition gwkjs_ns_class;
static JSClassRef gwkjs_ns_class_ref = NULL;

GWKJS_DEFINE_PRIV_FROM_JS(Ns, gwkjs_ns_class)

static JSValueRef
ns_get_property(JSContextRef context,
                JSObjectRef obj,
                JSStringRef property_name,
                JSValueRef* exception)
{
    Ns *priv = NULL;
    char *name = NULL;
    GIRepository *repo = NULL;
    GIBaseInfo *info;
    JSValueRef ret = NULL;
    gboolean defined;

    name = gwkjs_jsstring_to_cstring(property_name);

    /* let Object.prototype resolve these */
    if (strcmp(name, "valueOf") == 0 ||
        strcmp(name, "toString") == 0) {
        goto out;
    }

    priv = priv_from_js(obj);
    gwkjs_debug_jsprop(GWKJS_DEBUG_GNAMESPACE,
                       "Resolve prop '%s' hook obj %p priv %p",
                       name, (void *)obj, priv);

    if (priv == NULL) {
        goto out;
    }

    // If the module was already included, the default proto system
    // should return the property, not this method.
    if (g_hash_table_contains(priv->modules, name))
        goto out;

    repo = g_irepository_get_default();

    info = g_irepository_find_by_name(repo, priv->gi_namespace, name);
    if (info == NULL) {
        /* No property defined, but no error either, so return TRUE */
        goto out;
    }

    gwkjs_debug(GWKJS_DEBUG_GNAMESPACE,
                "Found info type %s for '%s' in namespace '%s'",
                gwkjs_info_type_name(g_base_info_get_type(info)),
                g_base_info_get_name(info),
                g_base_info_get_namespace(info));

    g_hash_table_replace(priv->modules, g_strdup(name), NULL);
    if ((ret = gwkjs_define_info(context, obj, info, &defined))) {
//        g_base_info_unref(info);
//XXX: Does it return THIS?!
//        if (defined)
//            objp.set(obj); /* we defined the property in this object */
    } else {
        g_hash_table_remove(priv->modules, name);
        gwkjs_debug(GWKJS_DEBUG_GNAMESPACE,
                    "Failed to define info '%s'",
                    g_base_info_get_name(info));

        g_base_info_unref(info);
    }

 out:
    g_free(name);
    return ret;
}

static JSValueRef
get_name (JSContextRef context,
          JSObjectRef obj,
          JSStringRef propertyName,
          JSValueRef* exception)
{
    Ns *priv;
    JSValueRef retval = NULL;

    priv = priv_from_js(obj);

    if (priv == NULL)
        goto out;

    retval = gwkjs_cstring_to_jsvalue(context,  priv->gi_namespace);

 out:
    return retval;
}

GWKJS_NATIVE_CONSTRUCTOR_DEFINE_ABSTRACT(ns)

static void
ns_finalize(JSObjectRef obj)
{
    Ns *priv;

    priv = priv_from_js(obj);
    gwkjs_debug_lifecycle(GWKJS_DEBUG_GNAMESPACE,
                        "finalize, obj %p priv %p", obj, priv);
    if (priv == NULL)
        return; /* we are the prototype, not a real instance */

    if (priv->gi_namespace)
        g_free(priv->gi_namespace);

    GWKJS_DEC_COUNTER(ns);
    g_slice_free(Ns, priv);
}

JSStaticValue gwkjs_ns_proto_props[] = {
    { "__name__", get_name, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
    { 0, 0, 0, 0 }
};

JSClassDefinition gwkjs_ns_class = {
    0,                         //     Version
    kJSPropertyAttributeNone,  //     JSClassAttributes
    "GIRepositoryNamespace",   //     const char* className;
    NULL,                      //     JSClassRef parentClass;
    gwkjs_ns_proto_props,      //     const JSStaticValue*                staticValues;
    NULL,                      //     const JSStaticFunction*             staticFunctions;
    NULL,                      //     JSObjectInitializeCallback          initialize;
    ns_finalize,               //     JSObjectFinalizeCallback            finalize;
    NULL,                      //     JSObjectHasPropertyCallback         hasProperty;

    ns_get_property,           //     JSObjectGetPropertyCallback         getProperty;

    NULL,                      //     JSObjectSetPropertyCallback         setProperty;
    NULL,                      //     JSObjectDeletePropertyCallback      deleteProperty;
    NULL,                      //     JSObjectGetPropertyNamesCallback    getPropertyNames;
    NULL,                      //     JSObjectCallAsFunctionCallback      callAsFunction;
    gwkjs_ns_constructor,      //     JSObjectCallAsConstructorCallback   callAsConstructor;
    NULL,                      //     JSObjectHasInstanceCallback         hasInstance;
    NULL,                      //     JSObjectConvertToTypeCallback       convertToType;
};

static JSObjectRef
ns_new(JSContextRef context,
       const char   *ns_name)
{
    Ns *priv = NULL;
    JSObjectRef ret = NULL;
    JSObjectRef global = NULL;
    gboolean found = FALSE;
    JSObjectRef proto = NULL;
    JSValueRef exception = NULL;

    // XXX: NOT THREAD SAFE?
    if (!gwkjs_ns_class_ref) {
        gwkjs_ns_class_ref = JSClassCreate(&gwkjs_ns_class);
    }

    global = gwkjs_get_import_global(context);
    if (!(found = gwkjs_object_has_property(context,
                                            global,
                                            gwkjs_ns_class.className))) {
        proto = JSObjectMake(context,
                             gwkjs_ns_class_ref,
                             NULL);

        gwkjs_object_set_property(context, global,
                                  gwkjs_ns_class.className,
                                  proto,
                                  GWKJS_PROTO_PROP_FLAGS,
                                  &exception);

        if (exception)
           g_error("Can't init class %s", gwkjs_ns_class.className);

        gwkjs_debug(GWKJS_DEBUG_IMPORTER, "Initialized class %s prototype %p",
                    gwkjs_ns_class.className, proto);
    } else {
        JSValueRef proto_val = gwkjs_object_get_property(context,
                                                         global,
                                                         gwkjs_ns_class.className,
                                                         &exception);

        if (exception || proto_val == NULL || !JSValueIsObject(context, proto_val))
            g_error("Can't get protoType for class %s", gwkjs_ns_class.className);

        proto = JSValueToObject(context, proto_val, NULL);
    }
    g_assert(proto != NULL);

    ret = JSObjectMake(context, gwkjs_ns_class_ref, NULL);

    if (ret == NULL)
        return ret;

    JSObjectSetPrototype(context, ret, proto);

    priv = g_slice_new0(Ns);
    GWKJS_INC_COUNTER(ns);

    g_assert(priv_from_js(ret) == NULL);
    JSObjectSetPrivate(ret, priv);

    gwkjs_debug_lifecycle(GWKJS_DEBUG_GNAMESPACE, "ns constructor, obj %p priv %p", ret, priv);

    priv = priv_from_js(ret);
    priv->modules = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);

    priv->gi_namespace = g_strdup(ns_name);
    return ret;
}

JSObjectRef
gwkjs_create_ns(JSContextRef context,
                const char   *ns_name)
{
    return ns_new(context, ns_name);
}
<commit_msg>Some small fixes for NS<commit_after>/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/*
 * Copyright (c) 2008  litl, LLC
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <config.h>

#include "ns.h"
#include "repo.h"
#include "param.h"
#include <gwkjs/gwkjs-module.h>
#include <gwkjs/compat.h>

#include <util/log.h>
#include <girepository.h>

#include <string.h>

typedef struct {
    char *gi_namespace;
    GHashTable *modules;
} Ns;

extern JSClassDefinition gwkjs_ns_class;
static JSClassRef gwkjs_ns_class_ref = NULL;

GWKJS_DEFINE_PRIV_FROM_JS(Ns, gwkjs_ns_class)

static JSValueRef
ns_get_property(JSContextRef context,
                JSObjectRef obj,
                JSStringRef property_name,
                JSValueRef* exception)
{
    Ns *priv = NULL;
    char *name = NULL;
    GIRepository *repo = NULL;
    GIBaseInfo *info;
    JSValueRef ret = NULL;
    gboolean defined;

    name = gwkjs_jsstring_to_cstring(property_name);

    /* let Object.prototype resolve these */
    if (strcmp(name, "valueOf") == 0 ||
        strcmp(name, "toString") == 0) {
        goto out;
    }

    priv = priv_from_js(obj);
    gwkjs_debug_jsprop(GWKJS_DEBUG_GNAMESPACE,
                       "Resolve prop '%s' hook obj %p priv %p",
                       name, (void *)obj, priv);

    if (priv == NULL) {
        goto out;
    }

    // If the module was already included, the default proto system
    // should return the property, not this method.
    if (g_hash_table_contains(priv->modules, name))
        goto out;

    repo = g_irepository_get_default();

    info = g_irepository_find_by_name(repo, priv->gi_namespace, name);
    if (info == NULL) {
        /* No property defined, but no error either, so return TRUE */
        goto out;
    }

    gwkjs_debug(GWKJS_DEBUG_GNAMESPACE,
                "Found info type %s for '%s' in namespace '%s'",
                gwkjs_info_type_name(g_base_info_get_type(info)),
                g_base_info_get_name(info),
                g_base_info_get_namespace(info));

    g_hash_table_replace(priv->modules, g_strdup(name), NULL);
    if ((ret = gwkjs_define_info(context, obj, info, &defined))) {
        g_base_info_unref(info);
//XXX: Does it return THIS?!
//        if (defined)
//            objp.set(obj); /* we defined the property in this object */
    } else {
        g_hash_table_remove(priv->modules, name);
        gwkjs_debug(GWKJS_DEBUG_GNAMESPACE,
                    "Failed to define info '%s'",
                    g_base_info_get_name(info));

        g_base_info_unref(info);
    }

 out:
    g_free(name);
    return ret;
}

static JSValueRef
get_name (JSContextRef context,
          JSObjectRef obj,
          JSStringRef propertyName,
          JSValueRef* exception)
{
    Ns *priv;
    JSValueRef retval = NULL;

    priv = priv_from_js(obj);

    if (priv == NULL)
        goto out;

    retval = gwkjs_cstring_to_jsvalue(context,  priv->gi_namespace);

 out:
    return retval;
}

GWKJS_NATIVE_CONSTRUCTOR_DEFINE_ABSTRACT(ns)

static void
ns_finalize(JSObjectRef obj)
{
    Ns *priv;

    priv = priv_from_js(obj);
    gwkjs_debug_lifecycle(GWKJS_DEBUG_GNAMESPACE,
                        "finalize, obj %p priv %p", obj, priv);
    if (priv == NULL)
        return; /* we are the prototype, not a real instance */

    if (priv->gi_namespace)
        g_free(priv->gi_namespace);

    GWKJS_DEC_COUNTER(ns);
    g_slice_free(Ns, priv);
}

JSStaticValue gwkjs_ns_proto_props[] = {
    { "__name__", get_name, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
    { 0, 0, 0, 0 }
};

JSClassDefinition gwkjs_ns_class = {
    0,                         //     Version
    kJSPropertyAttributeNone,  //     JSClassAttributes
    "GIRepositoryNamespace",   //     const char* className;
    NULL,                      //     JSClassRef parentClass;
    gwkjs_ns_proto_props,      //     const JSStaticValue*                staticValues;
    NULL,                      //     const JSStaticFunction*             staticFunctions;
    NULL,                      //     JSObjectInitializeCallback          initialize;
    ns_finalize,               //     JSObjectFinalizeCallback            finalize;
    NULL,                      //     JSObjectHasPropertyCallback         hasProperty;

    ns_get_property,           //     JSObjectGetPropertyCallback         getProperty;

    NULL,                      //     JSObjectSetPropertyCallback         setProperty;
    NULL,                      //     JSObjectDeletePropertyCallback      deleteProperty;
    NULL,                      //     JSObjectGetPropertyNamesCallback    getPropertyNames;
    NULL,                      //     JSObjectCallAsFunctionCallback      callAsFunction;
    gwkjs_ns_constructor,      //     JSObjectCallAsConstructorCallback   callAsConstructor;
    NULL,                      //     JSObjectHasInstanceCallback         hasInstance;
    NULL,                      //     JSObjectConvertToTypeCallback       convertToType;
};

static JSObjectRef
ns_new(JSContextRef context,
       const char   *ns_name)
{
    Ns *priv = NULL;
    JSObjectRef ret = NULL;
    JSObjectRef global = NULL;
    gboolean found = FALSE;
    JSObjectRef proto = NULL;
    JSValueRef exception = NULL;

    // XXX: NOT THREAD SAFE?
    if (!gwkjs_ns_class_ref) {
        gwkjs_ns_class_ref = JSClassCreate(&gwkjs_ns_class);
        JSClassRetain(gwkjs_ns_class_ref);
    }

    global = gwkjs_get_import_global(context);
    if (!(found = gwkjs_object_has_property(context,
                                            global,
                                            gwkjs_ns_class.className))) {
        proto = JSObjectMake(context,
                             gwkjs_ns_class_ref,
                             NULL);

        gwkjs_object_set_property(context, global,
                                  gwkjs_ns_class.className,
                                  proto,
                                  GWKJS_PROTO_PROP_FLAGS,
                                  &exception);

        if (exception)
           g_error("Can't init class %s", gwkjs_ns_class.className);

        gwkjs_debug(GWKJS_DEBUG_IMPORTER, "Initialized class %s prototype %p",
                    gwkjs_ns_class.className, proto);
    } else {
        JSValueRef proto_val = gwkjs_object_get_property(context,
                                                         global,
                                                         gwkjs_ns_class.className,
                                                         &exception);

        if (exception || proto_val == NULL || !JSValueIsObject(context, proto_val))
            g_error("Can't get protoType for class %s", gwkjs_ns_class.className);

        proto = JSValueToObject(context, proto_val, NULL);
    }
    g_assert(proto != NULL);

    ret = JSObjectMake(context, gwkjs_ns_class_ref, NULL);

    if (ret == NULL)
        return ret;

    JSObjectSetPrototype(context, ret, proto);

    priv = g_slice_new0(Ns);
    GWKJS_INC_COUNTER(ns);

    g_assert(priv_from_js(ret) == NULL);
    JSObjectSetPrivate(ret, priv);

    gwkjs_debug_lifecycle(GWKJS_DEBUG_GNAMESPACE, "ns constructor, obj %p priv %p", ret, priv);

    priv = priv_from_js(ret);
    priv->modules = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);

    priv->gi_namespace = g_strdup(ns_name);
    return ret;
}

JSObjectRef
gwkjs_create_ns(JSContextRef context,
                const char   *ns_name)
{
    return ns_new(context, ns_name);
}
<|endoftext|>


<commit_before>#include "cmake.h"
#include "filesystem.h"
#include "dialogs.h"
#include "config.h"
#include "terminal.h"

//Temporary fix for current Arch Linux boost linking problem
#ifdef __GNUC_PREREQ
#if __GNUC_PREREQ(5,1)
#include <regex>
#define REGEX_NS std
#endif
#endif
#ifndef REGEX_NS
#include <boost/regex.hpp>
#define REGEX_NS boost
#endif

CMake::CMake(const boost::filesystem::path &path) {
  const auto find_cmake_project=[this](const boost::filesystem::path &cmake_path) {
    for(auto &line: filesystem::read_lines(cmake_path)) {
      const static REGEX_NS::regex project_regex("^ *project *\\(.*$", REGEX_NS::regex::icase);
      REGEX_NS::smatch sm;
      if(REGEX_NS::regex_match(line, sm, project_regex))
        return true;
    }
    return false;
  };

  auto search_path=boost::filesystem::is_directory(path)?path:path.parent_path();
  while(true) {
    auto search_cmake_path=search_path/"CMakeLists.txt";
    if(boost::filesystem::exists(search_cmake_path)) {
      paths.emplace(paths.begin(), search_cmake_path);
      if(find_cmake_project(search_cmake_path)) {
        project_path=search_path;
        break;
      }
    }
    if(search_path==search_path.root_directory())
      break;
    search_path=search_path.parent_path();
  }
}

bool CMake::update_default_build(const boost::filesystem::path &default_build_path, bool force) {
  if(project_path.empty())
    return false;

  if(!boost::filesystem::exists(project_path/"CMakeLists.txt"))
    return false;

  if(default_build_path.empty())
    return false;
  if(!boost::filesystem::exists(default_build_path)) {
    boost::system::error_code ec;
    boost::filesystem::create_directories(default_build_path, ec);
    if(ec) {
      Terminal::get().print("Error: could not create "+default_build_path.string()+": "+ec.message()+"\n", true);
      return false;
    }
  }

  if(!force && boost::filesystem::exists(default_build_path/"compile_commands.json"))
    return true;

  auto compile_commands_path=default_build_path/"compile_commands.json";
  Dialog::Message message("Creating/updating default build");
  auto exit_status=Terminal::get().process(Config::get().project.cmake_command+" "+
                                           filesystem::escape_argument(project_path)+" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path);
  message.hide();
  if(exit_status==EXIT_SUCCESS) {
#ifdef _WIN32 //Temporary fix to MSYS2's libclang
    auto compile_commands_file=filesystem::read(compile_commands_path);
    size_t pos=0;
    while((pos=compile_commands_file.find("-I/", pos))!=std::string::npos) {
      if(pos+3<compile_commands_file.size()) {
        std::string drive;
        drive+=compile_commands_file[pos+3];
        compile_commands_file.replace(pos, 4, "-I"+drive+":");
      }
      else
        break;
    }
    filesystem::write(compile_commands_path, compile_commands_file);
#endif
    return true;
  }
  return false;
}

bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path, bool force) {
  if(project_path.empty())
    return false;

  if(!boost::filesystem::exists(project_path/"CMakeLists.txt"))
    return false;

  if(debug_build_path.empty())
    return false;
  if(!boost::filesystem::exists(debug_build_path)) {
    boost::system::error_code ec;
    boost::filesystem::create_directories(debug_build_path, ec);
    if(ec) {
      Terminal::get().print("Error: could not create "+debug_build_path.string()+": "+ec.message()+"\n", true);
      return false;
    }
  }

  if(!force && boost::filesystem::exists(debug_build_path/"CMakeCache.txt"))
    return true;

  std::unique_ptr<Dialog::Message> message;
  message=std::unique_ptr<Dialog::Message>(new Dialog::Message("Creating/updating debug build"));
  auto exit_status=Terminal::get().process(Config::get().project.cmake_command+" "+
                                           filesystem::escape_argument(project_path)+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path);
  if(message)
    message->hide();
  if(exit_status==EXIT_SUCCESS)
    return true;
  return false;
}

boost::filesystem::path CMake::get_executable(const boost::filesystem::path &file_path) {
  auto executables = get_functions_parameters("add_executable");

  //Attempt to find executable based add_executable files and opened tab
  boost::filesystem::path executable_path;
  if(!file_path.empty()) {
    for(auto &executable: executables) {
      if(executable.second.size()>1) {
        for(size_t c=1;c<executable.second.size();c++) {
          if(executable.second[c]==file_path.filename()) {
            executable_path=executable.first.parent_path()/executable.second[0];
            break;
          }
        }
      }
      if(!executable_path.empty())
        break;
    }
  }
  if(executable_path.empty() && executables.size()>0 && executables[0].second.size()>0)
    executable_path=executables[0].first.parent_path()/executables[0].second[0];

  return executable_path;
}

void CMake::read_files() {
  for(auto &path: paths)
    files.emplace_back(filesystem::read(path));
}

void CMake::remove_tabs() {
  for(auto &file: files) {
    for(auto &chr: file) {
      if(chr=='\t')
        chr=' ';
    }
  }
}

void CMake::remove_comments() {
  for(auto &file: files) {
    size_t pos=0;
    size_t comment_start;
    bool inside_comment=false;
    while(pos<file.size()) {
      if(!inside_comment && file[pos]=='#') {
        comment_start=pos;
        inside_comment=true;
      }
      if(inside_comment && file[pos]=='\n') {
        file.erase(comment_start, pos-comment_start);
        pos-=pos-comment_start;
        inside_comment=false;
      }
      pos++;
    }
    if(inside_comment)
      file.erase(comment_start);
  }
}

void CMake::remove_newlines_inside_parentheses() {
  for(auto &file: files) {
    size_t pos=0;
    bool inside_para=false;
    bool inside_quote=false;
    char last_char=0;
    while(pos<file.size()) {
      if(!inside_quote && file[pos]=='"' && last_char!='\\')
        inside_quote=true;
      else if(inside_quote && file[pos]=='"' && last_char!='\\')
        inside_quote=false;

      else if(!inside_quote && file[pos]=='(')
        inside_para=true;
      else if(!inside_quote && file[pos]==')')
        inside_para=false;

      else if(inside_para && file[pos]=='\n')
        file.replace(pos, 1, 1, ' ');
      last_char=file[pos];
      pos++;
    }
  }
}

void CMake::find_variables() {
  for(auto &file: files) {
    size_t pos=0;
    while(pos<file.size()) {
      auto start_line=pos;
      auto end_line=file.find('\n', start_line);
      if(end_line==std::string::npos)
        end_line=file.size();
      if(end_line>start_line) {
        auto line=file.substr(start_line, end_line-start_line);
        REGEX_NS::smatch sm;
        const static REGEX_NS::regex set_regex("^ *set *\\( *([A-Za-z_][A-Za-z_0-9]*) +(.*)\\) *$", REGEX_NS::regex::icase);
        if(REGEX_NS::regex_match(line, sm, set_regex)) {
          auto data=sm[2].str();
          while(data.size()>0 && data.back()==' ')
            data.pop_back();
          parse_variable_parameters(data);
          variables[sm[1].str()]=data;
        }
        else {
          const static REGEX_NS::regex project_regex("^ *project *\\( *([^ ]+).*\\) *$", REGEX_NS::regex::icase);
          if(REGEX_NS::regex_match(line, sm, project_regex)) {
            auto data=sm[1].str();
            parse_variable_parameters(data);
            variables["CMAKE_PROJECT_NAME"]=data; //TODO: is this variable deprecated/non-standard?
            variables["PROJECT_NAME"]=data;
          }
        }
      }
      pos=end_line+1;
    }
  }
}

void CMake::parse_variable_parameters(std::string &data) {
  size_t pos=0;
  bool inside_quote=false;
  char last_char=0;
  while(pos<data.size()) {
    if(!inside_quote && data[pos]=='"' && last_char!='\\') {
      inside_quote=true;
      data.erase(pos, 1); //TODO: instead remove quote-mark if pasted into a quote, for instance: "test${test}test"<-remove quotes from ${test}
      pos--;
    }
    else if(inside_quote && data[pos]=='"' && last_char!='\\') {
      inside_quote=false;
      data.erase(pos, 1); //TODO: instead remove quote-mark if pasted into a quote, for instance: "test${test}test"<-remove quotes from ${test}
      pos--;
    }
    else if(!inside_quote && data[pos]==' ' && pos+1<data.size() && data[pos+1]==' ') {
      data.erase(pos, 1);
      pos--;
    }

    if(pos!=static_cast<size_t>(-1))
      last_char=data[pos];
    pos++;
  }
  for(auto &var: variables) {
    auto pos=data.find("${"+var.first+'}');
    while(pos!=std::string::npos) {
      data.replace(pos, var.first.size()+3, var.second);
      pos=data.find("${"+var.first+'}');
    }
  }

  //Remove variables we do not know:
  pos=data.find("${");
  auto pos_end=data.find("}", pos+2);
  while(pos!=std::string::npos && pos_end!=std::string::npos) {
    data.erase(pos, pos_end-pos+1);
    pos=data.find("${");
    pos_end=data.find("}", pos+2);
  }
}

void CMake::parse() {
  read_files();
  remove_tabs();
  remove_comments();
  remove_newlines_inside_parentheses();
  find_variables();
  parsed=true;
}

std::vector<std::string> CMake::get_function_parameters(std::string &data) {
  std::vector<std::string> parameters;
  size_t pos=0;
  size_t parameter_pos=0;
  bool inside_quote=false;
  char last_char=0;
  while(pos<data.size()) {
    if(!inside_quote && data[pos]=='"' && last_char!='\\') {
      inside_quote=true;
      data.erase(pos, 1);
      pos--;
    }
    else if(inside_quote && data[pos]=='"' && last_char!='\\') {
      inside_quote=false;
      data.erase(pos, 1);
      pos--;
    }
    else if(!inside_quote && pos+1<data.size() && data[pos]==' ' && data[pos+1]==' ') {
      data.erase(pos, 1);
      pos--;
    }
    else if(!inside_quote && data[pos]==' ') {
      parameters.emplace_back(data.substr(parameter_pos, pos-parameter_pos));
      if(pos+1<data.size())
        parameter_pos=pos+1;
    }

    if(pos!=static_cast<size_t>(-1))
      last_char=data[pos];
    pos++;
  }
  parameters.emplace_back(data.substr(parameter_pos));
  for(auto &var: variables) {
    for(auto &parameter: parameters) {
      auto pos=parameter.find("${"+var.first+'}');
      while(pos!=std::string::npos) {
        parameter.replace(pos, var.first.size()+3, var.second);
        pos=parameter.find("${"+var.first+'}');
      }
    }
  }
  return parameters;
}

std::vector<std::pair<boost::filesystem::path, std::vector<std::string> > > CMake::get_functions_parameters(const std::string &name) {
  const REGEX_NS::regex function_regex("^ *"+name+" *\\( *(.*)\\) *$", REGEX_NS::regex::icase);
  if(!parsed)
    parse();
  std::vector<std::pair<boost::filesystem::path, std::vector<std::string> > > functions;
  size_t file_c=0;
  for(auto &file: files) {
    size_t pos=0;
    while(pos<file.size()) {
      auto start_line=pos;
      auto end_line=file.find('\n', start_line);
      if(end_line==std::string::npos)
        end_line=file.size();
      if(end_line>start_line) {
        auto line=file.substr(start_line, end_line-start_line);
        REGEX_NS::smatch sm;
        if(REGEX_NS::regex_match(line, sm, function_regex)) {
          auto data=sm[1].str();
          while(data.size()>0 && data.back()==' ')
            data.pop_back();
          auto parameters=get_function_parameters(data);
          functions.emplace(functions.begin(), paths[file_c], parameters);
        }
      }
      pos=end_line+1;
    }
    file_c++;
  }
  return functions;
}
<commit_msg>extended fix to MSYS2's libclang to '-isystem'<commit_after>#include "cmake.h"
#include "filesystem.h"
#include "dialogs.h"
#include "config.h"
#include "terminal.h"

//Temporary fix for current Arch Linux boost linking problem
#ifdef __GNUC_PREREQ
#if __GNUC_PREREQ(5,1)
#include <regex>
#define REGEX_NS std
#endif
#endif
#ifndef REGEX_NS
#include <boost/regex.hpp>
#define REGEX_NS boost
#endif

CMake::CMake(const boost::filesystem::path &path) {
  const auto find_cmake_project=[this](const boost::filesystem::path &cmake_path) {
    for(auto &line: filesystem::read_lines(cmake_path)) {
      const static REGEX_NS::regex project_regex("^ *project *\\(.*$", REGEX_NS::regex::icase);
      REGEX_NS::smatch sm;
      if(REGEX_NS::regex_match(line, sm, project_regex))
        return true;
    }
    return false;
  };

  auto search_path=boost::filesystem::is_directory(path)?path:path.parent_path();
  while(true) {
    auto search_cmake_path=search_path/"CMakeLists.txt";
    if(boost::filesystem::exists(search_cmake_path)) {
      paths.emplace(paths.begin(), search_cmake_path);
      if(find_cmake_project(search_cmake_path)) {
        project_path=search_path;
        break;
      }
    }
    if(search_path==search_path.root_directory())
      break;
    search_path=search_path.parent_path();
  }
}

bool CMake::update_default_build(const boost::filesystem::path &default_build_path, bool force) {
  if(project_path.empty())
    return false;

  if(!boost::filesystem::exists(project_path/"CMakeLists.txt"))
    return false;

  if(default_build_path.empty())
    return false;
  if(!boost::filesystem::exists(default_build_path)) {
    boost::system::error_code ec;
    boost::filesystem::create_directories(default_build_path, ec);
    if(ec) {
      Terminal::get().print("Error: could not create "+default_build_path.string()+": "+ec.message()+"\n", true);
      return false;
    }
  }

  if(!force && boost::filesystem::exists(default_build_path/"compile_commands.json"))
    return true;

  auto compile_commands_path=default_build_path/"compile_commands.json";
  Dialog::Message message("Creating/updating default build");
  auto exit_status=Terminal::get().process(Config::get().project.cmake_command+" "+
                                           filesystem::escape_argument(project_path)+" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path);
  message.hide();
  if(exit_status==EXIT_SUCCESS) {
#ifdef _WIN32 //Temporary fix to MSYS2's libclang
    auto compile_commands_file=filesystem::read(compile_commands_path);
    auto replace_drive = [&compile_commands_file](const std::string& param) {
      size_t pos=0;
      auto param_size = param.length();
      while((pos=compile_commands_file.find(param+"/", pos))!=std::string::npos) {
        if(pos+param_size+1<compile_commands_file.size())
          compile_commands_file.replace(pos, param_size+2, param+compile_commands_file[pos+param_size+1]+":");
        else
          break;
      }
    };
    replace_drive("-I");
    replace_drive("-isystem ");
    filesystem::write(compile_commands_path, compile_commands_file);
#endif
    return true;
  }
  return false;
}

bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path, bool force) {
  if(project_path.empty())
    return false;

  if(!boost::filesystem::exists(project_path/"CMakeLists.txt"))
    return false;

  if(debug_build_path.empty())
    return false;
  if(!boost::filesystem::exists(debug_build_path)) {
    boost::system::error_code ec;
    boost::filesystem::create_directories(debug_build_path, ec);
    if(ec) {
      Terminal::get().print("Error: could not create "+debug_build_path.string()+": "+ec.message()+"\n", true);
      return false;
    }
  }

  if(!force && boost::filesystem::exists(debug_build_path/"CMakeCache.txt"))
    return true;

  std::unique_ptr<Dialog::Message> message;
  message=std::unique_ptr<Dialog::Message>(new Dialog::Message("Creating/updating debug build"));
  auto exit_status=Terminal::get().process(Config::get().project.cmake_command+" "+
                                           filesystem::escape_argument(project_path)+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path);
  if(message)
    message->hide();
  if(exit_status==EXIT_SUCCESS)
    return true;
  return false;
}

boost::filesystem::path CMake::get_executable(const boost::filesystem::path &file_path) {
  auto executables = get_functions_parameters("add_executable");

  //Attempt to find executable based add_executable files and opened tab
  boost::filesystem::path executable_path;
  if(!file_path.empty()) {
    for(auto &executable: executables) {
      if(executable.second.size()>1) {
        for(size_t c=1;c<executable.second.size();c++) {
          if(executable.second[c]==file_path.filename()) {
            executable_path=executable.first.parent_path()/executable.second[0];
            break;
          }
        }
      }
      if(!executable_path.empty())
        break;
    }
  }
  if(executable_path.empty() && executables.size()>0 && executables[0].second.size()>0)
    executable_path=executables[0].first.parent_path()/executables[0].second[0];

  return executable_path;
}

void CMake::read_files() {
  for(auto &path: paths)
    files.emplace_back(filesystem::read(path));
}

void CMake::remove_tabs() {
  for(auto &file: files) {
    for(auto &chr: file) {
      if(chr=='\t')
        chr=' ';
    }
  }
}

void CMake::remove_comments() {
  for(auto &file: files) {
    size_t pos=0;
    size_t comment_start;
    bool inside_comment=false;
    while(pos<file.size()) {
      if(!inside_comment && file[pos]=='#') {
        comment_start=pos;
        inside_comment=true;
      }
      if(inside_comment && file[pos]=='\n') {
        file.erase(comment_start, pos-comment_start);
        pos-=pos-comment_start;
        inside_comment=false;
      }
      pos++;
    }
    if(inside_comment)
      file.erase(comment_start);
  }
}

void CMake::remove_newlines_inside_parentheses() {
  for(auto &file: files) {
    size_t pos=0;
    bool inside_para=false;
    bool inside_quote=false;
    char last_char=0;
    while(pos<file.size()) {
      if(!inside_quote && file[pos]=='"' && last_char!='\\')
        inside_quote=true;
      else if(inside_quote && file[pos]=='"' && last_char!='\\')
        inside_quote=false;

      else if(!inside_quote && file[pos]=='(')
        inside_para=true;
      else if(!inside_quote && file[pos]==')')
        inside_para=false;

      else if(inside_para && file[pos]=='\n')
        file.replace(pos, 1, 1, ' ');
      last_char=file[pos];
      pos++;
    }
  }
}

void CMake::find_variables() {
  for(auto &file: files) {
    size_t pos=0;
    while(pos<file.size()) {
      auto start_line=pos;
      auto end_line=file.find('\n', start_line);
      if(end_line==std::string::npos)
        end_line=file.size();
      if(end_line>start_line) {
        auto line=file.substr(start_line, end_line-start_line);
        REGEX_NS::smatch sm;
        const static REGEX_NS::regex set_regex("^ *set *\\( *([A-Za-z_][A-Za-z_0-9]*) +(.*)\\) *$", REGEX_NS::regex::icase);
        if(REGEX_NS::regex_match(line, sm, set_regex)) {
          auto data=sm[2].str();
          while(data.size()>0 && data.back()==' ')
            data.pop_back();
          parse_variable_parameters(data);
          variables[sm[1].str()]=data;
        }
        else {
          const static REGEX_NS::regex project_regex("^ *project *\\( *([^ ]+).*\\) *$", REGEX_NS::regex::icase);
          if(REGEX_NS::regex_match(line, sm, project_regex)) {
            auto data=sm[1].str();
            parse_variable_parameters(data);
            variables["CMAKE_PROJECT_NAME"]=data; //TODO: is this variable deprecated/non-standard?
            variables["PROJECT_NAME"]=data;
          }
        }
      }
      pos=end_line+1;
    }
  }
}

void CMake::parse_variable_parameters(std::string &data) {
  size_t pos=0;
  bool inside_quote=false;
  char last_char=0;
  while(pos<data.size()) {
    if(!inside_quote && data[pos]=='"' && last_char!='\\') {
      inside_quote=true;
      data.erase(pos, 1); //TODO: instead remove quote-mark if pasted into a quote, for instance: "test${test}test"<-remove quotes from ${test}
      pos--;
    }
    else if(inside_quote && data[pos]=='"' && last_char!='\\') {
      inside_quote=false;
      data.erase(pos, 1); //TODO: instead remove quote-mark if pasted into a quote, for instance: "test${test}test"<-remove quotes from ${test}
      pos--;
    }
    else if(!inside_quote && data[pos]==' ' && pos+1<data.size() && data[pos+1]==' ') {
      data.erase(pos, 1);
      pos--;
    }

    if(pos!=static_cast<size_t>(-1))
      last_char=data[pos];
    pos++;
  }
  for(auto &var: variables) {
    auto pos=data.find("${"+var.first+'}');
    while(pos!=std::string::npos) {
      data.replace(pos, var.first.size()+3, var.second);
      pos=data.find("${"+var.first+'}');
    }
  }

  //Remove variables we do not know:
  pos=data.find("${");
  auto pos_end=data.find("}", pos+2);
  while(pos!=std::string::npos && pos_end!=std::string::npos) {
    data.erase(pos, pos_end-pos+1);
    pos=data.find("${");
    pos_end=data.find("}", pos+2);
  }
}

void CMake::parse() {
  read_files();
  remove_tabs();
  remove_comments();
  remove_newlines_inside_parentheses();
  find_variables();
  parsed=true;
}

std::vector<std::string> CMake::get_function_parameters(std::string &data) {
  std::vector<std::string> parameters;
  size_t pos=0;
  size_t parameter_pos=0;
  bool inside_quote=false;
  char last_char=0;
  while(pos<data.size()) {
    if(!inside_quote && data[pos]=='"' && last_char!='\\') {
      inside_quote=true;
      data.erase(pos, 1);
      pos--;
    }
    else if(inside_quote && data[pos]=='"' && last_char!='\\') {
      inside_quote=false;
      data.erase(pos, 1);
      pos--;
    }
    else if(!inside_quote && pos+1<data.size() && data[pos]==' ' && data[pos+1]==' ') {
      data.erase(pos, 1);
      pos--;
    }
    else if(!inside_quote && data[pos]==' ') {
      parameters.emplace_back(data.substr(parameter_pos, pos-parameter_pos));
      if(pos+1<data.size())
        parameter_pos=pos+1;
    }

    if(pos!=static_cast<size_t>(-1))
      last_char=data[pos];
    pos++;
  }
  parameters.emplace_back(data.substr(parameter_pos));
  for(auto &var: variables) {
    for(auto &parameter: parameters) {
      auto pos=parameter.find("${"+var.first+'}');
      while(pos!=std::string::npos) {
        parameter.replace(pos, var.first.size()+3, var.second);
        pos=parameter.find("${"+var.first+'}');
      }
    }
  }
  return parameters;
}

std::vector<std::pair<boost::filesystem::path, std::vector<std::string> > > CMake::get_functions_parameters(const std::string &name) {
  const REGEX_NS::regex function_regex("^ *"+name+" *\\( *(.*)\\) *$", REGEX_NS::regex::icase);
  if(!parsed)
    parse();
  std::vector<std::pair<boost::filesystem::path, std::vector<std::string> > > functions;
  size_t file_c=0;
  for(auto &file: files) {
    size_t pos=0;
    while(pos<file.size()) {
      auto start_line=pos;
      auto end_line=file.find('\n', start_line);
      if(end_line==std::string::npos)
        end_line=file.size();
      if(end_line>start_line) {
        auto line=file.substr(start_line, end_line-start_line);
        REGEX_NS::smatch sm;
        if(REGEX_NS::regex_match(line, sm, function_regex)) {
          auto data=sm[1].str();
          while(data.size()>0 && data.back()==' ')
            data.pop_back();
          auto parameters=get_function_parameters(data);
          functions.emplace(functions.begin(), paths[file_c], parameters);
        }
      }
      pos=end_line+1;
    }
    file_c++;
  }
  return functions;
}
<|endoftext|>