<commit_before>#include "mmu.h"

#include "boot.h"
#include "util/log.h"
#include "video/video.h"

#include <cstdlib>

MMU::MMU(Cartridge& inCartridge, Video& inVideo) :
    cartridge(inCartridge),
    video(inVideo)
{
    memory = std::vector<u8>(0xFFFF);
}

u8 MMU::read(const Address address) const {
    if (address.in_range(0x0, 0x7FFF)) {
        if (address.in_range(0x0, 0xFF) && boot_rom_active()) {
            return bootDMG[address.value()];
        }
        return cartridge.read(address);
    }

    /* VRAM */
    if (address.in_range(0x8000, 0x9FFF)) {
        return memory_read(address);
    }

    /* External (cartridge) RAM */
    if (address.in_range(0xA000, 0xBFFF)) {
        /* log_warn("Attempting to read from cartridge RAM"); */
        return memory_read(address);
    }

    /* Internal work RAM */
    if (address.in_range(0xC000, 0xDFFF)) {
        return memory_read(address);
    }

    if (address.in_range(0xE000, 0xFDFF)) {
        /* log_warn("Attempting to read from mirrored work RAM"); */
        auto mirrored_address = Address(address.value() - 0x2000);
        return memory_read(mirrored_address);
    }

    /* Mapped IO */
    if (address.in_range(0xFF00, 0xFF7F)) {
        return read_io(address);
    }

    /* Zero Page ram */
    if (address.in_range(0xFF80, 0xFFFE)) {
        return memory_read(address);
    }

    /* Interrupt Enable register */
    if (address.value() == 0xFFFF) {
        return memory_read(address);
    }

    log_error("Attempted to read from unmapped memory address %X", address.value());
    exit(1);
}

u8 MMU::memory_read(const Address address) const {
    return memory[address.value()];
}

u8 MMU::read_io(const Address address) const {
    switch (address.value()) {
        case 0xFF42:
            return video.scroll_y.value();

        case 0xFF44:
            return video.line.value();

        /* Disable boot rom switch */
        case 0xFF50:
            return memory_read(address);

        default:
            log_error("Read from unknown IO address 0x%x", address.value());
            exit(1);
    }
}

void MMU::write(const Address address, const u8 byte) {
    if (address.in_range(0x0000, 0x7FFF)) {
        /* log_warn("Attempting to write to cartridge ROM"); */
    }

    /* VRAM */
    if (address.in_range(0x7FFF, 0x9FFF)) {
        memory_write(address, byte);
        return;
    }

    /* External (cartridge) RAM */
    if (address.in_range(0xA000, 0xBFFF)) {
        memory_write(address, byte);
        return;
    }

    /* Internal work RAM */
    if (address.in_range(0xC000, 0xDFFF)) {
        memory_write(address, byte);
        return;
    }

    /* Mirrored RAM */
    if (address.in_range(0xE000, 0xFDFF)) {
        /* log_warn("Attempting to write to mirrored work RAM"); */
        auto mirrored_address = Address(address.value() - 0x2000);
        memory_write(mirrored_address, byte);
        return;
    }

    /* Mapped IO */
    if (address.in_range(0xFF00, 0xFF7F)) {
        write_io(address, byte);
        return;
    }

    if (address.in_range(0xFEA0, 0xFEFF)) {
        /* log_warn("Attempting to write to unusable memory"); */
    }

    /* Zero Page ram */
    if (address.in_range(0xFF80, 0xFFFE)) {
        memory_write(address, byte);
        return;
    }

    /* Interrupt Enable register */
    if (address.value() == 0xFFFF) {
        memory_write(address, byte);
        return;
    }

    log_error("Attempted to write to unmapped memory address %X", address.value());
    exit(1);
}

void MMU::write_io(const Address address, const u8 byte) {
    switch (address.value()) {
        /* Serial data transfer (SB) */
        case 0xFF01:
            /* TODO */
            /* log_warn("%c", byte); */
            return;

        case 0xFF11:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF12:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF13:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF14:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF24:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF25:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF26:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

            /* Switch on LCD */
        case 0xFF40:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        /* Vertical Scroll Register */
        case 0xFF42:
            video.scroll_y.set(byte);
            return;

        /* LY - Line Y coordinate */
        case 0xFF44:
            /* "Writing will reset the counter */
            log_warn("Writing to FF44 will reset the line counter");
            return;

        case 0xFF47:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

            /* Disable boot rom switch */
        case 0xFF50:
            /* TODO */
            memory_write(address, byte);
            return;
    }
}

void MMU::memory_write(const Address address, const u8 byte) {
    memory[address.value()] = byte;
}

void MMU::write_word(const Address address, const u16 word) {
}

bool MMU::boot_rom_active() const {
    return read(0xFF50) != 0x1;
}
<commit_msg>Fix incorrect in_range for VRAM (use inclusive bound)<commit_after>#include "mmu.h"

#include "boot.h"
#include "util/log.h"
#include "video/video.h"

#include <cstdlib>

MMU::MMU(Cartridge& inCartridge, Video& inVideo) :
    cartridge(inCartridge),
    video(inVideo)
{
    memory = std::vector<u8>(0xFFFF);
}

u8 MMU::read(const Address address) const {
    if (address.in_range(0x0, 0x7FFF)) {
        if (address.in_range(0x0, 0xFF) && boot_rom_active()) {
            return bootDMG[address.value()];
        }
        return cartridge.read(address);
    }

    /* VRAM */
    if (address.in_range(0x8000, 0x9FFF)) {
        return memory_read(address);
    }

    /* External (cartridge) RAM */
    if (address.in_range(0xA000, 0xBFFF)) {
        /* log_warn("Attempting to read from cartridge RAM"); */
        return memory_read(address);
    }

    /* Internal work RAM */
    if (address.in_range(0xC000, 0xDFFF)) {
        return memory_read(address);
    }

    if (address.in_range(0xE000, 0xFDFF)) {
        /* log_warn("Attempting to read from mirrored work RAM"); */
        auto mirrored_address = Address(address.value() - 0x2000);
        return memory_read(mirrored_address);
    }

    /* Mapped IO */
    if (address.in_range(0xFF00, 0xFF7F)) {
        return read_io(address);
    }

    /* Zero Page ram */
    if (address.in_range(0xFF80, 0xFFFE)) {
        return memory_read(address);
    }

    /* Interrupt Enable register */
    if (address.value() == 0xFFFF) {
        return memory_read(address);
    }

    log_error("Attempted to read from unmapped memory address %X", address.value());
    exit(1);
}

u8 MMU::memory_read(const Address address) const {
    return memory[address.value()];
}

u8 MMU::read_io(const Address address) const {
    switch (address.value()) {
        case 0xFF42:
            return video.scroll_y.value();

        case 0xFF44:
            return video.line.value();

        /* Disable boot rom switch */
        case 0xFF50:
            return memory_read(address);

        default:
            log_error("Read from unknown IO address 0x%x", address.value());
            exit(1);
    }
}

void MMU::write(const Address address, const u8 byte) {
    if (address.in_range(0x0000, 0x7FFF)) {
        /* log_warn("Attempting to write to cartridge ROM"); */
    }

    /* VRAM */
    if (address.in_range(0x8000, 0x9FFF)) {
        memory_write(address, byte);
        return;
    }

    /* External (cartridge) RAM */
    if (address.in_range(0xA000, 0xBFFF)) {
        memory_write(address, byte);
        return;
    }

    /* Internal work RAM */
    if (address.in_range(0xC000, 0xDFFF)) {
        memory_write(address, byte);
        return;
    }

    /* Mirrored RAM */
    if (address.in_range(0xE000, 0xFDFF)) {
        /* log_warn("Attempting to write to mirrored work RAM"); */
        auto mirrored_address = Address(address.value() - 0x2000);
        memory_write(mirrored_address, byte);
        return;
    }

    /* Mapped IO */
    if (address.in_range(0xFF00, 0xFF7F)) {
        write_io(address, byte);
        return;
    }

    if (address.in_range(0xFEA0, 0xFEFF)) {
        /* log_warn("Attempting to write to unusable memory"); */
    }

    /* Zero Page ram */
    if (address.in_range(0xFF80, 0xFFFE)) {
        memory_write(address, byte);
        return;
    }

    /* Interrupt Enable register */
    if (address.value() == 0xFFFF) {
        memory_write(address, byte);
        return;
    }

    log_error("Attempted to write to unmapped memory address %X", address.value());
    exit(1);
}

void MMU::write_io(const Address address, const u8 byte) {
    switch (address.value()) {
        /* Serial data transfer (SB) */
        case 0xFF01:
            /* TODO */
            /* log_warn("%c", byte); */
            return;

        case 0xFF11:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF12:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF13:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF14:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF24:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF25:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        case 0xFF26:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

            /* Switch on LCD */
        case 0xFF40:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

        /* Vertical Scroll Register */
        case 0xFF42:
            video.scroll_y.set(byte);
            return;

        /* LY - Line Y coordinate */
        case 0xFF44:
            /* "Writing will reset the counter */
            log_warn("Writing to FF44 will reset the line counter");
            return;

        case 0xFF47:
            /* TODO */
            /* log_warn("Wrote to unknown address 0x%x", address.value()); */
            memory_write(address, byte);
            return;

            /* Disable boot rom switch */
        case 0xFF50:
            /* TODO */
            memory_write(address, byte);
            return;
    }
}

void MMU::memory_write(const Address address, const u8 byte) {
    memory[address.value()] = byte;
}

void MMU::write_word(const Address address, const u16 word) {
}

bool MMU::boot_rom_active() const {
    return read(0xFF50) != 0x1;
}
<|endoftext|>


<commit_before>#include <vector>
#include <iostream>

#include <ceres/ceres.h>

#include "prf.h"

using std::vector;

using Eigen::MatrixXd;
using Eigen::VectorXd;

using ceres::Solve;
using ceres::Solver;
using ceres::Problem;
using ceres::CostFunction;
using ceres::AutoDiffCostFunction;

using kpsf::load_prfs;

#define N_GAUSSIANS 4

class MOGResidual {

public:

    MOGResidual (MatrixXd img) : img_(img) {};

    template <typename T>
    bool operator() (const T* params, T* residuals) const {
        // Initialize the residuals.
        for (int i = 0; i < DIM_X; ++i)
            for (int j = 0; j < DIM_Y; ++j)
                residuals[i*DIM_Y+j] = T(img_(i, j));

        // Loop over the Gaussians and compute the model.
        for (int k = 0; k < N_GAUSSIANS; ++k) {
            // Ensure that the centers are in the frame.
            const T* pos = &(params[6*k+1]);
            if (pos[0] < T(0) || pos[0] >= T(DIM_X) ||
                    pos[1] < T(0) || pos[1] >= T(DIM_Y)) return false;

            // Compute the determinant and make sure that it's positive.
            const T* cov = &(params[6*k+3]);
            T det = cov[0] * cov[2] - cov[1] * cov[1];
            if (cov[0] <= T(0) || cov[2] <= T(0) || det <= T(0)) return false;

            // Pre-compute the normalization factor.
            T factor = params[6*k] / T(2*M_PI) / sqrt(det);

            // Loop over pixels and compute the model value.
            for (int i = 0; i < DIM_X; ++i) {
                for (int j = 0; j < DIM_Y; ++j) {
                    T dx = pos[0] - T(i),
                      dy = pos[1] - T(j),
                      x = cov[2] * dx - cov[1] * dy,
                      y = cov[0] * dy - cov[1] * dx,
                      v = (dx * x + dy * y) / det;
                    residuals[i*DIM_Y+j] -= factor * exp(T(-0.5) * v);
                }
            }
        }
        return true;
    };

private:

    MatrixXd img_;

};

int main ()
{
    int status;

    // Load the PRF files.
    vector<MatrixXd> prfs;
    status = load_prfs("../data/kplr07.4_2011265_prf.fits", &prfs);
    if (status) return status;

    // Initialize the parameters.
    VectorXd params(6*N_GAUSSIANS);
    for (int k = 0; k < N_GAUSSIANS; ++k) {
        params(6*k)   = 3000.0 / N_GAUSSIANS;
        params(6*k+1) = CENTER_X;
        params(6*k+2) = CENTER_Y;
        params(6*k+3) = (k + 1) * CENTER_X * CENTER_X;
        params(6*k+4) = 100.0;
        params(6*k+5) = (k + 1) * CENTER_Y * CENTER_Y;
    }

    // Set up the problem.
    Problem problem;
    CostFunction *cost =
        new AutoDiffCostFunction<MOGResidual, DIM_X*DIM_Y, 6*N_GAUSSIANS> (
            new MOGResidual (prfs[0]));
    problem.AddResidualBlock(cost, NULL, &(params(0)));

    // Set up the solver.
    Solver::Options options;
    options.max_num_iterations = 50 * N_GAUSSIANS;
    // options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY;
    options.linear_solver_type = ceres::DENSE_SCHUR;
    options.dense_linear_algebra_library_type = ceres::LAPACK;
    options.minimizer_progress_to_stdout = true;

    Solver::Summary summary;
    Solve(options, &problem, &summary);
    std::cout << summary.BriefReport() << std::endl;

    std::cout << params << std::endl;

    return 0;
}
<commit_msg>writing MOG output<commit_after>#include <cstdio>
#include <vector>
#include <iostream>

#include <fitsio.h>
#include <ceres/ceres.h>

// Ignore string warnings. It's cfitsio's fault!
#pragma GCC diagnostic ignored "-Wwrite-strings"

using std::vector;

using Eigen::MatrixXd;
using Eigen::VectorXd;

using ceres::Solve;
using ceres::Solver;
using ceres::Problem;
using ceres::CostFunction;
using ceres::AutoDiffCostFunction;

//
// Constants for the Kepler PRF model. These will be different for other
// models.
//
#define N_PSF_BASIS 5
#define OVERSAMPLE  50
#define DIM_X       550
#define DIM_Y       550
#define CENTER_X    275
#define CENTER_Y    275

//
// The number of Gaussians in our representation.
//
#define N_GAUSSIANS 3
#define PP_GAUSSIAN 6

//
// Read in the Kepler PRF basis images from a given FITS file. Returns a
// vector of images in Eigen::MatrixXd format. Status will be non-zero on
// failure.
//
int load_prfs (const char *fn, vector<MatrixXd>* prfs)
{
    fitsfile *f;
    int status = 0;

    // Open the file.
    if (fits_open_file(&f, fn, READONLY, &status)) {
        fits_report_error(stderr, status);
        return status;
    }

    // Read in the data.
    int anynull, hdutype, i;
    long fpixel = 1;
    double nullval = -1;
    *prfs = vector<MatrixXd>(N_PSF_BASIS);
    for (i = 0; i < N_PSF_BASIS; ++i) {
        // Move to the correct HDU.
        if (fits_movabs_hdu(f, i+2, &hdutype, &status)) {
            fits_report_error(stderr, status);
            return status;
        }

        // Allocate the matrix and read the image.
        (*prfs)[i] = MatrixXd(DIM_X, DIM_Y);
        if (fits_read_img(f, TDOUBLE, fpixel, DIM_X * DIM_Y, &nullval,
                          &((*prfs)[i](0)), &anynull, &status)) {
            fits_report_error(stderr, status);
            return status;
        }
    }

    // Close the file.
    if (fits_close_file(f, &status))
        fits_report_error(stderr, status);

    return status;
};

//
// Write the MOG representation of a PRF image to a file.
//
int write_mog (const char *fn, VectorXd params, int hdu)
{
    fitsfile *f;
    int status = 0;

    // Open the file.
    if (hdu == 1) {
        remove(fn);
        if (fits_create_file(&f, fn, &status)) {
            fits_report_error(stderr, status);
            return status;
        }
    } else {
        if (fits_open_file(&f, fn, READWRITE, &status)) {
            fits_report_error(stderr, status);
            return status;
        }

        // Move to the correct HDU.
    }

    // Create a new binary table.
    char* ttype[] = {"amp", "xpos", "ypos", "xvar", "covar", "yvar"},
        * tform[] = {"1D",  "1D",   "1D",   "1D",   "1D",    "1D"},
        * tunit[] = {"\0",  "\0",   "\0",   "\0",   "\0",    "\0"};
    if (fits_create_tbl(f, BINARY_TBL, N_GAUSSIANS, PP_GAUSSIAN, ttype, tform,
                        tunit, "MOG", &status)) {
        fits_report_error(stderr, status);
        return status;
    }

    // Coerce the data into the correct form.
    VectorXd amp(N_GAUSSIANS), xpos(N_GAUSSIANS), ypos(N_GAUSSIANS),
             xvar(N_GAUSSIANS), covar(N_GAUSSIANS), yvar(N_GAUSSIANS);
    for (int i = 0; i < N_GAUSSIANS; ++i) {
        amp(i)   = params(PP_GAUSSIAN*i);
        xpos(i)  = params(PP_GAUSSIAN*i + 1);
        ypos(i)  = params(PP_GAUSSIAN*i + 2);
        xvar(i)  = params(PP_GAUSSIAN*i + 3);
        covar(i) = params(PP_GAUSSIAN*i + 4);
        yvar(i)  = params(PP_GAUSSIAN*i + 5);
    }

    // Write the columns.
    fits_write_col(f, TDOUBLE, 1, 1, 1, N_GAUSSIANS, &(amp(0)), &status);
    fits_write_col(f, TDOUBLE, 2, 1, 1, N_GAUSSIANS, &(xpos(0)), &status);
    fits_write_col(f, TDOUBLE, 3, 1, 1, N_GAUSSIANS, &(ypos(0)), &status);
    fits_write_col(f, TDOUBLE, 4, 1, 1, N_GAUSSIANS, &(xvar(0)), &status);
    fits_write_col(f, TDOUBLE, 5, 1, 1, N_GAUSSIANS, &(covar(0)), &status);
    fits_write_col(f, TDOUBLE, 6, 1, 1, N_GAUSSIANS, &(yvar(0)), &status);

    // Clean up and return.
    if (status) fits_report_error(stderr, status);
    if (fits_close_file(f, &status)) fits_report_error(stderr, status);
    return status;
}

//
// The residual object used by Ceres to find the NLLS solution to the MOG
// representation model.
//
class MOGResidual {

public:

    MOGResidual (MatrixXd img) : img_(img) {};

    template <typename T>
    bool operator() (const T* params, T* residuals) const {
        // Initialize the residuals.
        for (int i = 0; i < DIM_X; ++i)
            for (int j = 0; j < DIM_Y; ++j)
                residuals[i*DIM_Y+j] = T(img_(i, j));

        // Loop over the Gaussians and compute the model.
        for (int k = 0; k < N_GAUSSIANS; ++k) {
            // Force the amplitudes to be positive.
            T amp = params[PP_GAUSSIAN*k];
            if (amp <= T(0)) return false;

            // Ensure that the centers are in the frame.
            T xpos = T(OVERSAMPLE) * params[PP_GAUSSIAN*k+1],
              ypos = T(OVERSAMPLE) * params[PP_GAUSSIAN*k+2];
            if (xpos < T(0) || xpos >= T(DIM_X) ||
                ypos < T(0) || ypos >= T(DIM_Y)) return false;

            // Compute the determinant and make sure that it's positive.
            T s2 = T(OVERSAMPLE * OVERSAMPLE),
              cov[] = {s2 * params[PP_GAUSSIAN*k+3],
                       s2 * params[PP_GAUSSIAN*k+4],
                       s2 * params[PP_GAUSSIAN*k+5]},
              det = cov[0] * cov[2] - cov[1] * cov[1];
            if (det <= T(0)) return false;

            // Pre-compute the normalization factor.
            T factor = amp / T(2*M_PI) / sqrt(det);

            // Loop over pixels and compute the model value.
            for (int i = 0; i < DIM_X; ++i) {
                for (int j = 0; j < DIM_Y; ++j) {
                    T dx = xpos - T(i),
                      dy = ypos - T(j),
                      x = cov[2] * dx - cov[1] * dy,
                      y = cov[0] * dy - cov[1] * dx,
                      v = (dx * x + dy * y) / det;
                    residuals[i*DIM_Y+j] -= factor * exp(T(-0.5) * v);
                }
            }
        }
        return true;
    };

private:

    MatrixXd img_;

};

int main ()
{
    int status;

    // Format the filenames.
    const char* infn = "../data/kplr07.4_2011265_prf.fits",
              * outfn = "../data/kplr07.4_2011265_prf.mog.fits";

    // Load the PRF files.
    vector<MatrixXd> prfs;
    status = load_prfs(infn, &prfs);
    if (status) return status;

    // Initialize the parameters.
    VectorXd params(PP_GAUSSIAN*N_GAUSSIANS);
    for (int k = 0; k < N_GAUSSIANS; ++k) {
        params(PP_GAUSSIAN*k)   = 300.0 / (k + 1);
        params(PP_GAUSSIAN*k+1) = CENTER_X / OVERSAMPLE;
        params(PP_GAUSSIAN*k+2) = CENTER_Y / OVERSAMPLE;
        params(PP_GAUSSIAN*k+3) = (k + 1) * 2.0;
        params(PP_GAUSSIAN*k+4) = 0.0;
        params(PP_GAUSSIAN*k+5) = (k + 1) * 2.0;
    }

    // Set up the problem.
    Problem problem;
    CostFunction *cost =
        new AutoDiffCostFunction<MOGResidual, DIM_X*DIM_Y, PP_GAUSSIAN*N_GAUSSIANS> (
            new MOGResidual (prfs[1]));
    problem.AddResidualBlock(cost, NULL, &(params(0)));

    // Set up the solver.
    Solver::Options options;
    options.max_num_iterations = 20 * N_GAUSSIANS;
    options.function_tolerance = 1e-5;
    // options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY;
    options.linear_solver_type = ceres::DENSE_SCHUR;
    options.dense_linear_algebra_library_type = ceres::LAPACK;
    options.minimizer_progress_to_stdout = true;

    Solver::Summary summary;
    Solve(options, &problem, &summary);
    std::cout << summary.BriefReport() << std::endl;

    std::cout << "Writing output file: " << outfn << std::endl;
    status = write_mog(outfn, params);
    if (status) return status;

    return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include <list>
#include <cassert>
#include <unordered_map>

template <typename _Kty, typename _Ty, size_t _Size>
class LRUCache
{
    const size_t maxSize_ = _Size;
    std::list<_Ty> values_;

public:
    using value_iterator = decltype(*values_.begin());
    using value_type = std::pair<const _Kty, _Ty>;
    using mapping_type = std::unordered_map<_Kty, value_iterator>;
    using iterator_type = typename mapping_type::iterator;

private:
    mapping_type mapping_;
    iterator_type oldest_ {};

public:
    LRUCache() = default;
    ~LRUCache() = default;
    LRUCache(const LRUCache&) = delete;
    LRUCache& operator=(const LRUCache&) = delete;
    LRUCache(LRUCache&&) = default;
    LRUCache& operator=(LRUCache&&) = default;

    bool insert(const value_type& value)
    {
        static_assert(_Size > 0, "Size must be greater than zero.");
        if (values_.size() == _Size)
        {
            auto itToRemove = values_.cbegin();
            values_.erase(itToRemove);

            assert(oldest_ != mapping_.end());
            mapping_.erase(oldest_);
            oldest_ = mapping_.begin();
        }

        values_.push_back(value.second);
        mapping_.insert({ value.first, values_.back() });

        assert(values_.size() == mapping_.size());
        if (values_.size() == 1)
        {
            oldest_ = mapping_.begin();
        }

        return true;
    }

    _Ty& operator[](const _Kty& key)
    {
        auto it = mapping_.find(key);
        if (it != mapping_.cend())
        {
            return it->second;
        }

        // TODO: remove dummy and brace initialize
        static _Ty dummy{};
        return dummy;
    }

    size_t size() const
    {
        return values_.size();
    }
};
<commit_msg>LRUCache operator[] implementation<commit_after>#pragma once

#include <list>
#include <cassert>
#include <unordered_map>

template <typename _Kty, typename _Ty, size_t _Size>
class LRUCache
{
    const size_t maxSize_ = _Size;
    std::list<_Ty> values_;

public:
    using value_iterator = decltype(*values_.begin());
    using value_type = std::pair<const _Kty, _Ty>;
    using mapping_type = std::unordered_map<_Kty, value_iterator>;
    using mapping_iterator = typename mapping_type::iterator;

private:
    mapping_type mapping_;
    mapping_iterator oldest_ {};

public:
    LRUCache() = default;
    ~LRUCache() = default;
    LRUCache(const LRUCache&) = delete;
    LRUCache& operator=(const LRUCache&) = delete;
    LRUCache(LRUCache&&) = default;
    LRUCache& operator=(LRUCache&&) = default;

    std::pair<mapping_iterator, bool> insert(const value_type& value)
    {
        static_assert(_Size > 0, "Size must be greater than zero.");
        if (values_.size() == _Size)
        {
            auto itToRemove = values_.cbegin();
            values_.erase(itToRemove);

            assert(oldest_ != mapping_.end());
            mapping_.erase(oldest_);
            oldest_ = mapping_.begin();
        }

        values_.push_back(value.second);
        auto result = mapping_.insert({ value.first, values_.back() });

        assert(values_.size() == mapping_.size());
        if (values_.size() == 1)
        {
            oldest_ = mapping_.begin();
        }

        return std::make_pair(result.first, true);
    }

    _Ty& operator[](const _Kty& key)
    {
        auto it = mapping_.find(key);
        if (it != mapping_.cend())
        {
            return it->second;
        }
        auto result = insert({ key , _Ty{} });
        return result.first->second;
    }

    size_t size() const
    {
        return values_.size();
    }
};
<|endoftext|>


<commit_before>// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "paymentservertests.h"

#include "optionsmodel.h"
#include "paymentrequestdata.h"

#include "amount.h"
#include "random.h"
#include "script/script.h"
#include "script/standard.h"
#include "util.h"
#include "utilstrencodings.h"

#include <openssl/x509.h>
#include <openssl/x509_vfy.h>

#include <QFileOpenEvent>
#include <QTemporaryFile>

X509 *parse_b64der_cert(const char* cert_data)
{
    std::vector<unsigned char> data = DecodeBase64(cert_data);
    assert(data.size() > 0);
    const unsigned char* dptr = &data[0];
    X509 *cert = d2i_X509(NULL, &dptr, data.size());
    assert(cert);
    return cert;
}

//
// Test payment request handling
//

static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsigned char>& data)
{
    RecipientCatcher sigCatcher;
    QObject::connect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
        &sigCatcher, SLOT(getRecipient(SendCoinsRecipient)));

    // Write data to a temp file:
    QTemporaryFile f;
    f.open();
    f.write((const char*)&data[0], data.size());
    f.close();

    // Create a QObject, install event filter from PaymentServer
    // and send a file open event to the object
    QObject object;
    object.installEventFilter(server);
    QFileOpenEvent event(f.fileName());
    // If sending the event fails, this will cause sigCatcher to be empty,
    // which will lead to a test failure anyway.
    QCoreApplication::sendEvent(&object, &event);

    QObject::disconnect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
        &sigCatcher, SLOT(getRecipient(SendCoinsRecipient)));

    // Return results from sigCatcher
    return sigCatcher.recipient;
}

void PaymentServerTests::paymentServerTests()
{
    SelectParams(CBaseChainParams::MAIN);
    OptionsModel optionsModel;
    PaymentServer* server = new PaymentServer(NULL, false);
    X509_STORE* caStore = X509_STORE_new();
    X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64));
    PaymentServer::LoadRootCAs(caStore);
    server->setOptionsModel(&optionsModel);
    server->uiReady();

    std::vector<unsigned char> data;
    SendCoinsRecipient r;
    QString merchant;

    // Now feed PaymentRequests to server, and observe signals it produces

    // This payment request validates directly against the
    // caCert1 certificate authority:
    data = DecodeBase64(paymentrequest1_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString("testmerchant.org"));

    // Signed, but expired, merchant cert in the request:
    data = DecodeBase64(paymentrequest2_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // 10-long certificate chain, all intermediates valid:
    data = DecodeBase64(paymentrequest3_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString("testmerchant8.org"));

    // Long certificate chain, with an expired certificate in the middle:
    data = DecodeBase64(paymentrequest4_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Validly signed, but by a CA not in our root CA list:
    data = DecodeBase64(paymentrequest5_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Try again with no root CA's, verifiedMerchant should be empty:
    caStore = X509_STORE_new();
    PaymentServer::LoadRootCAs(caStore);
    data = DecodeBase64(paymentrequest1_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Load second root certificate
    caStore = X509_STORE_new();
    X509_STORE_add_cert(caStore, parse_b64der_cert(caCert2_BASE64));
    PaymentServer::LoadRootCAs(caStore);

    QByteArray byteArray;

    // For the tests below we just need the payment request data from
    // paymentrequestdata.h parsed + stored in r.paymentRequest.
    //
    // These tests require us to bypass the following normal client execution flow
    // shown below to be able to explicitly just trigger a certain condition!
    //
    // handleRequest()
    // -> PaymentServer::eventFilter()
    //   -> PaymentServer::handleURIOrFile()
    //     -> PaymentServer::readPaymentRequestFromFile()
    //       -> PaymentServer::processPaymentRequest()

    // Contains a testnet paytoaddress, so payment request network doesn't match client network:
    data = DecodeBase64(paymentrequest1_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized, because network "main" is default, even for
    // uninizialized payment requests and that will fail our test here.
    QVERIFY(r.paymentRequest.IsInitialized());
    QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false);

    // Expired payment request (expires is set to 1 = 1970-01-01 00:00:01):
    data = DecodeBase64(paymentrequest2_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares 1 < GetTime() == false (treated as expired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);

    // Unexpired payment request (expires is set to 0x7FFFFFFFFFFFFFFF = max. int64_t):
    // 9223372036854775807 (uint64), 9223372036854775807 (int64_t) and -1 (int32_t)
    // -1 is 1969-12-31 23:59:59 (for a 32 bit time values)
    data = DecodeBase64(paymentrequest3_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares 9223372036854775807 < GetTime() == false (treated as unexpired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), false);

    // Unexpired payment request (expires is set to 0x8000000000000000 > max. int64_t, allowed uint64):
    // 9223372036854775808 (uint64), -9223372036854775808 (int64_t) and 0 (int32_t)
    // 0 is 1970-01-01 00:00:00 (for a 32 bit time values)
    data = DecodeBase64(paymentrequest4_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares -9223372036854775808 < GetTime() == true (treated as expired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);

    // Test BIP70 DoS protection:
    unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1];
    GetRandBytes(randData, sizeof(randData));
    // Write data to a temp file:
    QTemporaryFile tempFile;
    tempFile.open();
    tempFile.write((const char*)randData, sizeof(randData));
    tempFile.close();
    // compares 50001 <= BIP70_MAX_PAYMENTREQUEST_SIZE == false
    QCOMPARE(PaymentServer::verifySize(tempFile.size()), false);

    // Payment request with amount overflow (amount is set to 21000001 BTC):
    data = DecodeBase64(paymentrequest5_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // Extract address and amount from the request
    QList<std::pair<CScript, CAmount> > sendingTos = r.paymentRequest.getPayTo();
    Q_FOREACH (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
        CTxDestination dest;
        if (ExtractDestination(sendingTo.first, dest))
            QCOMPARE(PaymentServer::verifyAmount(sendingTo.second), false);
    }

    delete server;
}

void RecipientCatcher::getRecipient(SendCoinsRecipient r)
{
    recipient = r;
}
<commit_msg>Fixed compiler warning.<commit_after>// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "paymentservertests.h"

#include "optionsmodel.h"
#include "paymentrequestdata.h"

#include "amount.h"
#include "random.h"
#include "script/script.h"
#include "script/standard.h"
#include "util.h"
#include "utilstrencodings.h"

#include <openssl/x509.h>
#include <openssl/x509_vfy.h>

#include <QFileOpenEvent>
#include <QTemporaryFile>

X509 *parse_b64der_cert(const char* cert_data)
{
    std::vector<unsigned char> data = DecodeBase64(cert_data);
    assert(data.size() > 0);
    const unsigned char* dptr = &data[0];
    X509 *cert = d2i_X509(NULL, &dptr, data.size());
    assert(cert);
    return cert;
}

//
// Test payment request handling
//

static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsigned char>& data)
{
    RecipientCatcher sigCatcher;
    QObject::connect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
        &sigCatcher, SLOT(getRecipient(SendCoinsRecipient)));

    // Write data to a temp file:
    QTemporaryFile f;
    f.open();
    f.write((const char*)&data[0], data.size());
    f.close();

    // Create a QObject, install event filter from PaymentServer
    // and send a file open event to the object
    QObject object;
    object.installEventFilter(server);
    QFileOpenEvent event(f.fileName());
    // If sending the event fails, this will cause sigCatcher to be empty,
    // which will lead to a test failure anyway.
    QCoreApplication::sendEvent(&object, &event);

    QObject::disconnect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
        &sigCatcher, SLOT(getRecipient(SendCoinsRecipient)));

    // Return results from sigCatcher
    return sigCatcher.recipient;
}

void PaymentServerTests::paymentServerTests()
{
    SelectParams(CBaseChainParams::MAIN);
    OptionsModel optionsModel;
    PaymentServer* server = new PaymentServer(NULL, false);
    X509_STORE* caStore = X509_STORE_new();
    X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64));
    PaymentServer::LoadRootCAs(caStore);
    server->setOptionsModel(&optionsModel);
    server->uiReady();

    std::vector<unsigned char> data;
    SendCoinsRecipient r;
    QString merchant;

    // Now feed PaymentRequests to server, and observe signals it produces

    // This payment request validates directly against the
    // caCert1 certificate authority:
    data = DecodeBase64(paymentrequest1_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString("testmerchant.org"));

    // Signed, but expired, merchant cert in the request:
    data = DecodeBase64(paymentrequest2_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // 10-long certificate chain, all intermediates valid:
    data = DecodeBase64(paymentrequest3_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString("testmerchant8.org"));

    // Long certificate chain, with an expired certificate in the middle:
    data = DecodeBase64(paymentrequest4_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Validly signed, but by a CA not in our root CA list:
    data = DecodeBase64(paymentrequest5_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Try again with no root CA's, verifiedMerchant should be empty:
    caStore = X509_STORE_new();
    PaymentServer::LoadRootCAs(caStore);
    data = DecodeBase64(paymentrequest1_cert1_BASE64);
    r = handleRequest(server, data);
    r.paymentRequest.getMerchant(caStore, merchant);
    QCOMPARE(merchant, QString(""));

    // Load second root certificate
    caStore = X509_STORE_new();
    X509_STORE_add_cert(caStore, parse_b64der_cert(caCert2_BASE64));
    PaymentServer::LoadRootCAs(caStore);

    QByteArray byteArray;

    // For the tests below we just need the payment request data from
    // paymentrequestdata.h parsed + stored in r.paymentRequest.
    //
    // These tests require us to bypass the following normal client execution flow
    // shown below to be able to explicitly just trigger a certain condition!
    //
    // handleRequest()
    // -> PaymentServer::eventFilter()
    //   -> PaymentServer::handleURIOrFile()
    //     -> PaymentServer::readPaymentRequestFromFile()
    //       -> PaymentServer::processPaymentRequest()

    // Contains a testnet paytoaddress, so payment request network doesn't match client network:
    data = DecodeBase64(paymentrequest1_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized, because network "main" is default, even for
    // uninizialized payment requests and that will fail our test here.
    QVERIFY(r.paymentRequest.IsInitialized());
    QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false);

    // Expired payment request (expires is set to 1 = 1970-01-01 00:00:01):
    data = DecodeBase64(paymentrequest2_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares 1 < GetTime() == false (treated as expired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);

    // Unexpired payment request (expires is set to 0x7FFFFFFFFFFFFFFF = max. int64_t):
    // 9223372036854775807 (uint64), 9223372036854775807 (int64_t) and -1 (int32_t)
    // -1 is 1969-12-31 23:59:59 (for a 32 bit time values)
    data = DecodeBase64(paymentrequest3_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares 9223372036854775807 < GetTime() == false (treated as unexpired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), false);

    // Unexpired payment request (expires is set to 0x8000000000000000 > max. int64_t, allowed uint64):
    // 9223372036854775808 (uint64), -9223372036854775808 (int64_t) and 0 (int32_t)
    // 0 is 1970-01-01 00:00:00 (for a 32 bit time values)
    data = DecodeBase64(paymentrequest4_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // compares -9223372036854775808 < GetTime() == true (treated as expired payment request)
    QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);

    // Test BIP70 DoS protection:
    const qint64 bip70mps = BIP70_MAX_PAYMENTREQUEST_SIZE + 1;
    unsigned char* randData = new unsigned char[bip70mps];
    GetRandBytes(randData, sizeof(unsigned char) * bip70mps);
    // Write data to a temp file:
    QTemporaryFile tempFile;
    tempFile.open();
    tempFile.write((const char*)randData, sizeof(unsigned char) * bip70mps);
    tempFile.close();
    // compares 50001 <= BIP70_MAX_PAYMENTREQUEST_SIZE == false
    QCOMPARE(PaymentServer::verifySize(tempFile.size()), false);
    delete [] randData;

    // Payment request with amount overflow (amount is set to 21000001 BTC):
    data = DecodeBase64(paymentrequest5_cert2_BASE64);
    byteArray = QByteArray((const char*)&data[0], data.size());
    r.paymentRequest.parse(byteArray);
    // Ensure the request is initialized
    QVERIFY(r.paymentRequest.IsInitialized());
    // Extract address and amount from the request
    QList<std::pair<CScript, CAmount> > sendingTos = r.paymentRequest.getPayTo();
    Q_FOREACH (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
        CTxDestination dest;
        if (ExtractDestination(sendingTo.first, dest))
            QCOMPARE(PaymentServer::verifyAmount(sendingTo.second), false);
    }

    delete server;
}

void RecipientCatcher::getRecipient(SendCoinsRecipient r)
{
    recipient = r;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017-2018, Rauli Laine
 * 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 <plorth/plorth.hpp>

#include <cstring>
#include <fstream>
#include <stack>
#if PLORTH_ENABLE_MODULES
# include <unordered_set>
#endif

#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined(HAVE_SYSEXITS_H)
# include <sysexits.h>
#endif

#if !defined(EX_USAGE)
# define EX_USAGE 64
#endif

using namespace plorth;

static const char* script_filename = nullptr;
static bool flag_test_syntax = false;
static bool flag_fork = false;
#if PLORTH_ENABLE_MODULES
static std::unordered_set<unistring> imported_modules;
#endif

static void scan_arguments(const std::shared_ptr<runtime>&, int, char**);
#if PLORTH_ENABLE_MODULES
static void scan_module_path(const std::shared_ptr<runtime>&);
#endif
static inline bool is_console_interactive();
static void compile_and_run(const std::shared_ptr<context>&,
                            const std::string&,
                            const unistring&);
static void console_loop(const std::shared_ptr<context>&);
static void handle_error(const std::shared_ptr<context>&);

void initialize_repl_api(const std::shared_ptr<runtime>&);

int main(int argc, char** argv)
{
  memory::manager memory_manager;
  auto runtime = runtime::make(memory_manager);
  auto context = context::make(runtime);

#if PLORTH_ENABLE_MODULES
  scan_module_path(runtime);
#endif

  scan_arguments(runtime, argc, argv);

#if PLORTH_ENABLE_MODULES
  for (const auto& module_path : imported_modules)
  {
    if (!context->import(module_path))
    {
      handle_error(context);
    }
  }
#endif

  if (script_filename)
  {
    const unistring decoded_script_filename = utf8_decode(script_filename);
    std::ifstream is(script_filename, std::ios_base::in);

    if (is.good())
    {
      const std::string source = std::string(
        std::istreambuf_iterator<char>(is),
        std::istreambuf_iterator<char>()
        );

      is.close();
      context->clear();
#if PLORTH_ENABLE_MODULES
      context->filename(decoded_script_filename);
#endif
      compile_and_run(context, source, decoded_script_filename);
    } else {
      std::cerr << argv[0]
                << ": Unable to open file `"
                << script_filename
                << "' for reading."
                << std::endl;
      std::exit(EXIT_FAILURE);
    }
  }
  else if (is_console_interactive())
  {
    console_loop(context);
  } else {
    compile_and_run(
      context,
      std::string(
        std::istreambuf_iterator<char>(std::cin),
        std::istreambuf_iterator<char>()
      ),
      U"<stdin>"
    );
  }

  return EXIT_SUCCESS;
}

static void print_usage(std::ostream& out, const char* executable)
{
  out << std::endl
      << "Usage: "
      << executable
      << " [switches] [--] [programfile] [arguments]"
      << std::endl;
  out << "  -c        Check syntax only." << std::endl;
#if HAVE_FORK
  out << "  -f        Fork to background before executing script." << std::endl;
#endif
#if PLORTH_ENABLE_MODULES
  out << "  -r <path> Import module before executing script." << std::endl;
#endif
  out << "  --version Print the version." << std::endl;
  out << "  --help    Display this message." << std::endl;
  out << std::endl;
}

static void scan_arguments(const std::shared_ptr<class runtime>& runtime,
                           int argc,
                           char** argv)
{
  int offset = 1;

  while (offset < argc)
  {
    const char* arg = argv[offset++];

    if (!*arg)
    {
      continue;
    }
    else if (*arg != '-')
    {
      script_filename = arg;
      break;
    }
    else if (!arg[1])
    {
      break;
    }
    else if (arg[1] == '-')
    {
      if (!std::strcmp(arg, "--help"))
      {
        print_usage(std::cout, argv[0]);
        std::exit(EXIT_SUCCESS);
      }
      else if (!std::strcmp(arg, "--version"))
      {
        std::cerr << "Plorth " << utf8_encode(PLORTH_VERSION) << std::endl;
        std::exit(EXIT_SUCCESS);
      }
      else if (!std::strcmp(arg, "--"))
      {
        if (offset < argc)
        {
          script_filename = argv[offset++];
        }
        break;
      } else {
        std::cerr << "Unrecognized switch: " << arg << std::endl;
        print_usage(std::cerr, argv[0]);
        std::exit(EX_USAGE);
      }
    }
    for (int i = 1; arg[i]; ++i)
    {
      // TODO: Add support for these command line switches:
      // -e: Compile and execute inline script.
      switch (arg[i])
      {
      case 'c':
        flag_test_syntax = true;
        break;

      case 'f':
        flag_fork = true;
        break;

#if PLORTH_ENABLE_MODULES
      case 'r':
        if (offset < argc)
        {
          unistring module_path;

          if (!utf8_decode_test(argv[offset++], module_path))
          {
            std::cerr << "Unable to decode given module path." << std::endl;
            std::exit(EXIT_FAILURE);
          }
          imported_modules.insert(module_path);
          ++offset;
        } else {
          std::cerr << "Argument expected for the -r option." << std::endl;
          print_usage(std::cerr, argv[0]);
          std::exit(EX_USAGE);
        }
        break;
#else
      case 'r':
        std::cerr << "Modules have been disabled." << std::endl;
        std::exit(EXIT_FAILURE);
        break;
#endif

      case 'h':
        print_usage(std::cout, argv[0]);
        std::exit(EXIT_SUCCESS);
        break;

      default:
        std::cerr << "Unrecognized switch: `" << arg[i] << "'" << std::endl;
        print_usage(std::cerr, argv[0]);
        std::exit(EX_USAGE);
      }
    }
  }

  while (offset < argc)
  {
    runtime->arguments().push_back(utf8_decode(argv[offset++]));
  }
}

#if PLORTH_ENABLE_MODULES
static void scan_module_path(const std::shared_ptr<class runtime>& runtime)
{
#if defined(_WIN32)
  static const unichar path_separator = ';';
#else
  static const unichar path_separator = ':';
#endif
  auto& module_paths = runtime->module_paths();
  const char* begin = std::getenv("PLORTHPATH");
  const char* end = begin;

  if (end)
  {
    for (; *end; ++end)
    {
      if (*end != path_separator)
      {
        continue;
      }

      if (end - begin > 0)
      {
        module_paths.push_back(utf8_decode(std::string(begin, end - begin)));
      }
      begin = end + 1;
    }

    if (end - begin > 0)
    {
      module_paths.push_back(utf8_decode(std::string(begin, end - begin)));
    }
  }

#if defined(PLORTH_RUNTIME_LIBRARY_PATH)
  if (module_paths.empty())
  {
    module_paths.push_back(PLORTH_RUNTIME_LIBRARY_PATH);
  }
#endif
}
#endif

static inline bool is_console_interactive()
{
#if defined(HAVE_ISATTY)
  return isatty(fileno(stdin));
#else
  return false;
#endif
}

static void handle_error(const std::shared_ptr<context>& ctx)
{
  const std::shared_ptr<error>& err = ctx->error();

  if (err)
  {
    const auto position = err->position();

    std::cerr << "Error: ";
    if (position && (!position->filename.empty() || position->line))
    {
      std::cerr << *position << ':';
    }
    std::cerr << err->code() << " - " << err->message();
  } else {
    std::cerr << "Unknown error.";
  }
  std::cerr << std::endl;
  std::exit(EXIT_FAILURE);
}

static void compile_and_run(const std::shared_ptr<context>& ctx,
                            const std::string& input,
                            const unistring& filename)
{
  unistring source;
  std::shared_ptr<quote> script;

  if (!utf8_decode_test(input, source))
  {
    std::cerr << "Import error: Unable to decode source code as UTF-8." << std::endl;
    std::exit(EXIT_FAILURE);
  }

  if (!(script = ctx->compile(source, filename)))
  {
    handle_error(ctx);
    return;
  }

  if (flag_test_syntax)
  {
    std::cerr << "Syntax OK." << std::endl;
    std::exit(EXIT_SUCCESS);
    return;
  }

  if (flag_fork)
  {
#if HAVE_FORK
    if (fork())
    {
      std::exit(EXIT_SUCCESS);
    }
#else
    std::cerr << "Forking to background is not supported on this platform." << std::endl;
#endif
  }

  if (!script->call(ctx))
  {
    handle_error(ctx);
  }
}

static void count_open_braces(const std::string& input, std::stack<char>& open_braces)
{
  const std::size_t length = input.length();

  for (std::size_t i = 0; i < length; ++i)
  {
    switch (input[i])
    {
      case '#':
        return;

      case '(':
        open_braces.push(')');
        break;

      case '[':
        open_braces.push(']');
        break;

      case '{':
        open_braces.push('}');
        break;

      case ')':
      case ']':
      case '}':
        if (!open_braces.empty() && open_braces.top() == input[i])
        {
          open_braces.pop();
        }
        break;

      case '"':
        while (i < length)
        {
          if (input[i] == '"')
          {
            break;
          }
          else if (input[i] == '\\' && i + 1 < length)
          {
            i += 2;
          } else {
            ++i;
          }
        }
    }
  }
}

static void console_loop(const std::shared_ptr<class context>& context)
{
  int line_counter = 0;
  unistring source;
  std::stack<char> open_braces;

  initialize_repl_api(context->runtime());

  while (std::cin.good())
  {
    std::string line;

    std::cout << "plorth:"
              << ++line_counter
              << ':'
              << context->size()
              << (open_braces.empty() ? '>' : '*')
              << ' ';
    if (!std::getline(std::cin, line))
    {
      // Output final newline after ^D has been pressed by the user.
      std::cout << std::endl;
      break;
    }
    else if (!line.empty())
    {
      if (!utf8_decode_test(line, source))
      {
        std::cout << "Unable to decode given input as UTF-8." << std::endl;
        continue;
      }
      source.append(1, '\n');
      count_open_braces(line, open_braces);
      if (open_braces.empty())
      {
        const auto script = context->compile(source, U"<repl>", line_counter);

        source.clear();
        if (script)
        {
          script->call(context);
        }
        if (context->error())
        {
          const auto& error = context->error();

          if (error->position())
          {
            std::cout << *error->position() << ':';
          }
          std::cout << error << std::endl;
          context->clear_error();
        }
      }
    }
  }
}
<commit_msg>Fix a bug in the CLI argument parser<commit_after>/*
 * Copyright (c) 2017-2018, Rauli Laine
 * 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 <plorth/plorth.hpp>

#include <cstring>
#include <fstream>
#include <stack>
#if PLORTH_ENABLE_MODULES
# include <unordered_set>
#endif

#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined(HAVE_SYSEXITS_H)
# include <sysexits.h>
#endif

#if !defined(EX_USAGE)
# define EX_USAGE 64
#endif

using namespace plorth;

static const char* script_filename = nullptr;
static bool flag_test_syntax = false;
static bool flag_fork = false;
#if PLORTH_ENABLE_MODULES
static std::unordered_set<unistring> imported_modules;
#endif

static void scan_arguments(const std::shared_ptr<runtime>&, int, char**);
#if PLORTH_ENABLE_MODULES
static void scan_module_path(const std::shared_ptr<runtime>&);
#endif
static inline bool is_console_interactive();
static void compile_and_run(const std::shared_ptr<context>&,
                            const std::string&,
                            const unistring&);
static void console_loop(const std::shared_ptr<context>&);
static void handle_error(const std::shared_ptr<context>&);

void initialize_repl_api(const std::shared_ptr<runtime>&);

int main(int argc, char** argv)
{
  memory::manager memory_manager;
  auto runtime = runtime::make(memory_manager);
  auto context = context::make(runtime);

#if PLORTH_ENABLE_MODULES
  scan_module_path(runtime);
#endif

  scan_arguments(runtime, argc, argv);

#if PLORTH_ENABLE_MODULES
  for (const auto& module_path : imported_modules)
  {
    if (!context->import(module_path))
    {
      handle_error(context);
    }
  }
#endif

  if (script_filename)
  {
    const unistring decoded_script_filename = utf8_decode(script_filename);
    std::ifstream is(script_filename, std::ios_base::in);

    if (is.good())
    {
      const std::string source = std::string(
        std::istreambuf_iterator<char>(is),
        std::istreambuf_iterator<char>()
        );

      is.close();
      context->clear();
#if PLORTH_ENABLE_MODULES
      context->filename(decoded_script_filename);
#endif
      compile_and_run(context, source, decoded_script_filename);
    } else {
      std::cerr << argv[0]
                << ": Unable to open file `"
                << script_filename
                << "' for reading."
                << std::endl;
      std::exit(EXIT_FAILURE);
    }
  }
  else if (is_console_interactive())
  {
    console_loop(context);
  } else {
    compile_and_run(
      context,
      std::string(
        std::istreambuf_iterator<char>(std::cin),
        std::istreambuf_iterator<char>()
      ),
      U"<stdin>"
    );
  }

  return EXIT_SUCCESS;
}

static void print_usage(std::ostream& out, const char* executable)
{
  out << std::endl
      << "Usage: "
      << executable
      << " [switches] [--] [programfile] [arguments]"
      << std::endl;
  out << "  -c        Check syntax only." << std::endl;
#if HAVE_FORK
  out << "  -f        Fork to background before executing script." << std::endl;
#endif
#if PLORTH_ENABLE_MODULES
  out << "  -r <path> Import module before executing script." << std::endl;
#endif
  out << "  --version Print the version." << std::endl;
  out << "  --help    Display this message." << std::endl;
  out << std::endl;
}

static void scan_arguments(const std::shared_ptr<class runtime>& runtime,
                           int argc,
                           char** argv)
{
  int offset = 1;

  while (offset < argc)
  {
    const char* arg = argv[offset++];

    if (!*arg)
    {
      continue;
    }
    else if (*arg != '-')
    {
      script_filename = arg;
      break;
    }
    else if (!arg[1])
    {
      break;
    }
    else if (arg[1] == '-')
    {
      if (!std::strcmp(arg, "--help"))
      {
        print_usage(std::cout, argv[0]);
        std::exit(EXIT_SUCCESS);
      }
      else if (!std::strcmp(arg, "--version"))
      {
        std::cerr << "Plorth " << utf8_encode(PLORTH_VERSION) << std::endl;
        std::exit(EXIT_SUCCESS);
      }
      else if (!std::strcmp(arg, "--"))
      {
        if (offset < argc)
        {
          script_filename = argv[offset++];
        }
        break;
      } else {
        std::cerr << "Unrecognized switch: " << arg << std::endl;
        print_usage(std::cerr, argv[0]);
        std::exit(EX_USAGE);
      }
    }
    for (int i = 1; arg[i]; ++i)
    {
      // TODO: Add support for these command line switches:
      // -e: Compile and execute inline script.
      switch (arg[i])
      {
      case 'c':
        flag_test_syntax = true;
        break;

      case 'f':
        flag_fork = true;
        break;

#if PLORTH_ENABLE_MODULES
      case 'r':
        if (offset < argc)
        {
          unistring module_path;

          if (!utf8_decode_test(argv[offset++], module_path))
          {
            std::cerr << "Unable to decode given module path." << std::endl;
            std::exit(EXIT_FAILURE);
          }
          imported_modules.insert(module_path);
        } else {
          std::cerr << "Argument expected for the -r option." << std::endl;
          print_usage(std::cerr, argv[0]);
          std::exit(EX_USAGE);
        }
        break;
#else
      case 'r':
        std::cerr << "Modules have been disabled." << std::endl;
        std::exit(EXIT_FAILURE);
        break;
#endif

      case 'h':
        print_usage(std::cout, argv[0]);
        std::exit(EXIT_SUCCESS);
        break;

      default:
        std::cerr << "Unrecognized switch: `" << arg[i] << "'" << std::endl;
        print_usage(std::cerr, argv[0]);
        std::exit(EX_USAGE);
      }
    }
  }

  while (offset < argc)
  {
    runtime->arguments().push_back(utf8_decode(argv[offset++]));
  }
}

#if PLORTH_ENABLE_MODULES
static void scan_module_path(const std::shared_ptr<class runtime>& runtime)
{
#if defined(_WIN32)
  static const unichar path_separator = ';';
#else
  static const unichar path_separator = ':';
#endif
  auto& module_paths = runtime->module_paths();
  const char* begin = std::getenv("PLORTHPATH");
  const char* end = begin;

  if (end)
  {
    for (; *end; ++end)
    {
      if (*end != path_separator)
      {
        continue;
      }

      if (end - begin > 0)
      {
        module_paths.push_back(utf8_decode(std::string(begin, end - begin)));
      }
      begin = end + 1;
    }

    if (end - begin > 0)
    {
      module_paths.push_back(utf8_decode(std::string(begin, end - begin)));
    }
  }

#if defined(PLORTH_RUNTIME_LIBRARY_PATH)
  if (module_paths.empty())
  {
    module_paths.push_back(PLORTH_RUNTIME_LIBRARY_PATH);
  }
#endif
}
#endif

static inline bool is_console_interactive()
{
#if defined(HAVE_ISATTY)
  return isatty(fileno(stdin));
#else
  return false;
#endif
}

static void handle_error(const std::shared_ptr<context>& ctx)
{
  const std::shared_ptr<error>& err = ctx->error();

  if (err)
  {
    const auto position = err->position();

    std::cerr << "Error: ";
    if (position && (!position->filename.empty() || position->line))
    {
      std::cerr << *position << ':';
    }
    std::cerr << err->code() << " - " << err->message();
  } else {
    std::cerr << "Unknown error.";
  }
  std::cerr << std::endl;
  std::exit(EXIT_FAILURE);
}

static void compile_and_run(const std::shared_ptr<context>& ctx,
                            const std::string& input,
                            const unistring& filename)
{
  unistring source;
  std::shared_ptr<quote> script;

  if (!utf8_decode_test(input, source))
  {
    std::cerr << "Import error: Unable to decode source code as UTF-8." << std::endl;
    std::exit(EXIT_FAILURE);
  }

  if (!(script = ctx->compile(source, filename)))
  {
    handle_error(ctx);
    return;
  }

  if (flag_test_syntax)
  {
    std::cerr << "Syntax OK." << std::endl;
    std::exit(EXIT_SUCCESS);
    return;
  }

  if (flag_fork)
  {
#if HAVE_FORK
    if (fork())
    {
      std::exit(EXIT_SUCCESS);
    }
#else
    std::cerr << "Forking to background is not supported on this platform." << std::endl;
#endif
  }

  if (!script->call(ctx))
  {
    handle_error(ctx);
  }
}

static void count_open_braces(const std::string& input, std::stack<char>& open_braces)
{
  const std::size_t length = input.length();

  for (std::size_t i = 0; i < length; ++i)
  {
    switch (input[i])
    {
      case '#':
        return;

      case '(':
        open_braces.push(')');
        break;

      case '[':
        open_braces.push(']');
        break;

      case '{':
        open_braces.push('}');
        break;

      case ')':
      case ']':
      case '}':
        if (!open_braces.empty() && open_braces.top() == input[i])
        {
          open_braces.pop();
        }
        break;

      case '"':
        while (i < length)
        {
          if (input[i] == '"')
          {
            break;
          }
          else if (input[i] == '\\' && i + 1 < length)
          {
            i += 2;
          } else {
            ++i;
          }
        }
    }
  }
}

static void console_loop(const std::shared_ptr<class context>& context)
{
  int line_counter = 0;
  unistring source;
  std::stack<char> open_braces;

  initialize_repl_api(context->runtime());

  while (std::cin.good())
  {
    std::string line;

    std::cout << "plorth:"
              << ++line_counter
              << ':'
              << context->size()
              << (open_braces.empty() ? '>' : '*')
              << ' ';
    if (!std::getline(std::cin, line))
    {
      // Output final newline after ^D has been pressed by the user.
      std::cout << std::endl;
      break;
    }
    else if (!line.empty())
    {
      if (!utf8_decode_test(line, source))
      {
        std::cout << "Unable to decode given input as UTF-8." << std::endl;
        continue;
      }
      source.append(1, '\n');
      count_open_braces(line, open_braces);
      if (open_braces.empty())
      {
        const auto script = context->compile(source, U"<repl>", line_counter);

        source.clear();
        if (script)
        {
          script->call(context);
        }
        if (context->error())
        {
          const auto& error = context->error();

          if (error->position())
          {
            std::cout << *error->position() << ':';
          }
          std::cout << error << std::endl;
          context->clear_error();
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 nyorain
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt

///\file
///\brief Defines the CompatibleFunction (CompFunc typedef'd) template class.

#pragma once

#ifndef NYTL_INCLUDE_COMPFUNC_HPP
#define NYTL_INCLUDE_COMPFUNC_HPP

#include <nytl/functionTraits.hpp>
#include <nytl/bits/tupleMap.inl>

#include <type_traits>
#include <utility>
#include <tuple>
#include <functional>

namespace nytl
{

//TODO: always correct reference (rvalue, lvalue) handling, perfmance improvement
//does a lamba object ever use the std::function stack storage buffer most impl have?
//custom function object (type erasure) to use then to stroe the function?
//correct forwarding of args

//Not specified, use the function-signature template <Ret(Args...)> like std::function.
template<typename S> class CompatibleFunction;

///\brief A Function object that is able to hold all functions with a compatible signature.
///\ingroup function
template<typename R, typename... A>
class CompatibleFunction<R(A...)>
{
public:
	using Ret = R;
	using Signature = Ret(A...);
	using Function = std::function<Signature>;
	using CompFuncType = CompatibleFunction<Signature>;
	using ArgsTuple = std::tuple<A...>;

protected:
	Function func_ {};

public:
	CompatibleFunction() = default;
	~CompatibleFunction() = default;

	//constructor
	template<typename F, typename = std::enable_if_t<IsCallable<F>>>
	CompatibleFunction(F func) noexcept { set(func); }

	template<typename F, typename O, typename = std::enable_if_t<IsCallable<F>>>
	CompatibleFunction(F func, O& object) noexcept { set(memberCallback(func, object)); }

	CompatibleFunction(const CompFuncType& other) noexcept
		: func_(other.func_) {}
	template<typename Sig> CompatibleFunction(const CompatibleFunction<Sig>& other) noexcept
		{ set(other.func_); }

	//assignement
	template<typename F, typename = typename std::enable_if_t<IsCallable<F>>>
	CompFuncType& operator=(F func) noexcept { set(func); return *this; }

	CompFuncType& operator=(const CompFuncType& other) noexcept
		{ func_ = other.func_; return *this; }
	template<typename Sig> CompFuncType& operator=(const CompatibleFunction<Sig>& other) noexcept
		{ set(other.func_); return *this; }

	//set
	template<typename F>
	void set(F func) noexcept
	{
		using FuncTraits = FunctionTraits<F>;
		using RealArgsTuple = typename FuncTraits::ArgTuple;
		using RealRet = typename FuncTraits::ReturnType;
		using MapType = detail::TupleMap<ArgsTuple, RealArgsTuple, RealRet>;
		constexpr auto first = SeqGet<0, typename MapType::Seq, true>;

		static_assert(std::is_convertible<R, RealRet>::value, "Return types not compatible");
		static_assert(MapType::Seq::size() == FuncTraits::ArgSize, "Arguments not compatible");
		static_assert(first != std::size_t(-1), "Arguments not compatible");

		func_ = [=](A... args) -> Ret {
				return static_cast<Ret>(MapType::map(func, std::forward<A>(args)...));
			};
	}

	//get
	Function function() const noexcept { return func_; }

	//call
	Ret call(A... args) const { func_(std::forward<A>(args)...); }
	Ret operator()(A... args) const { func_(std::forward<A>(args)...); }

	operator bool() const { return function(); }
};

template<typename... A>
class CompatibleFunction<void(A...)>
{
public:
	using Ret = void;
	using Signature = Ret(A...);
	using Function = std::function<Signature>;
	using CompFuncType = CompatibleFunction<Signature>;
	using ArgsTuple = std::tuple<A...>;

protected:
	Function func_;

public:
	CompatibleFunction() = default;
	~CompatibleFunction() = default;

	//constructor
	template<typename F, typename = typename std::enable_if_t<IsCallable<F>>>
	CompatibleFunction(F func) noexcept { set(func); }

	template<typename F, typename O, typename = typename std::enable_if_t<IsCallable<F>>>
	CompatibleFunction(F func, O object) noexcept { set(memberCallback(func, object)); }

	CompatibleFunction(const CompFuncType& other) noexcept
		: func_(other.func_) {}
	template<typename Sig> CompatibleFunction(const CompatibleFunction<Sig>& other) noexcept
		{ set(other.func_); }

	//assignement
	template<typename F, typename = typename std::enable_if_t<IsCallable<F>>>
	CompFuncType& operator=(F func) noexcept { set(func); return *this; }

	CompFuncType& operator=(const CompFuncType& other) noexcept
		{ func_ = other.func_; return *this; }
	template<typename Sig> CompFuncType& operator=(const CompatibleFunction<Sig>& other) noexcept
		{ set(other.func_); return *this; }

	//set
	template<typename F>
	void set(F func) noexcept
	{
		using FuncTraits = FunctionTraits<F>;
		using RealArgsTuple = typename FuncTraits::ArgTuple;
		using MapType = detail::TupleMap<ArgsTuple, RealArgsTuple, void>;
		constexpr auto first = SeqGet<0, typename MapType::Seq, true>;

		static_assert(MapType::Seq::size() == FuncTraits::ArgSize, "Arguments not compatible");
		static_assert(first != std::size_t(-1), "Arguments not compatible");

		func_ = [=](A... args) -> Ret {
				MapType::map(func, std::forward<A>(args)...);
			};
	}

	//get
	Function function() const noexcept { return func_; }

	//call
	Ret call(A... args) const { func_(std::forward<A>(args)...); }
	Ret operator()(A... args) const { func_(std::forward<A>(args)...); }

	operator bool() const { return function(); }
};

//typedef CompFunc
template<typename S> using CompFunc = CompatibleFunction<S>;

}

#endif //heade guard
<commit_msg>fix small compFunc copy ctor bug<commit_after>// Copyright (c) 2016 nyorain
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt

///\file
///\brief Defines the CompatibleFunction (CompFunc typedef'd) template class.

#pragma once

#ifndef NYTL_INCLUDE_COMPFUNC_HPP
#define NYTL_INCLUDE_COMPFUNC_HPP

#include <nytl/functionTraits.hpp>
#include <nytl/bits/tupleMap.inl>

#include <type_traits>
#include <utility>
#include <tuple>
#include <functional>

namespace nytl
{

//TODO: always correct reference (rvalue, lvalue) handling, perfmance improvement
//does a lamba object ever use the std::function stack storage buffer most impl have?
//custom function object (type erasure) to use then to stroe the function?
//correct forwarding of args

//Not specified, use the function-signature template <Ret(Args...)> like std::function.
template<typename S> class CompatibleFunction;

///\brief A Function object that is able to hold all functions with a compatible signature.
///\ingroup function
template<typename R, typename... A>
class CompatibleFunction<R(A...)>
{
public:
	using Ret = R;
	using Signature = Ret(A...);
	using Function = std::function<Signature>;
	using CompFuncType = CompatibleFunction<Signature>;
	using ArgsTuple = std::tuple<A...>;

protected:
	Function func_ {};

public:
	CompatibleFunction() = default;
	~CompatibleFunction() = default;

	//constructor
	template<typename F, typename = std::enable_if_t<IsCallable<F>>>
	CompatibleFunction(F func) noexcept { set(func); }

	template<typename F, typename O, typename = std::enable_if_t<IsCallable<F>>>
	CompatibleFunction(F func, O& object) noexcept { set(memberCallback(func, object)); }

	CompatibleFunction(const CompFuncType& other) noexcept
		: func_(other.func_) {}
	template<typename Sig> CompatibleFunction(const CompatibleFunction<Sig>& other) noexcept
		{ set(other.function()); }

	//assignement
	template<typename F, typename = typename std::enable_if_t<IsCallable<F>>>
	CompFuncType& operator=(F func) noexcept { set(func); return *this; }

	CompFuncType& operator=(const CompFuncType& other) noexcept
		{ func_ = other.func_; return *this; }
	template<typename Sig> CompFuncType& operator=(const CompatibleFunction<Sig>& other) noexcept
		{ set(other.function()); return *this; }

	//set
	template<typename F>
	void set(F func) noexcept
	{
		using FuncTraits = FunctionTraits<F>;
		using RealArgsTuple = typename FuncTraits::ArgTuple;
		using RealRet = typename FuncTraits::ReturnType;
		using MapType = detail::TupleMap<ArgsTuple, RealArgsTuple, RealRet>;
		constexpr auto first = SeqGet<0, typename MapType::Seq, true>;

		static_assert(std::is_convertible<R, RealRet>::value, "Return types not compatible");
		static_assert(MapType::Seq::size() == FuncTraits::ArgSize, "Arguments not compatible");
		static_assert(first != std::size_t(-1), "Arguments not compatible");

		func_ = [=](A... args) -> Ret {
				return static_cast<Ret>(MapType::map(func, std::forward<A>(args)...));
			};
	}

	//get
	Function function() const noexcept { return func_; }

	//call
	Ret call(A... args) const { func_(std::forward<A>(args)...); }
	Ret operator()(A... args) const { func_(std::forward<A>(args)...); }

	operator bool() const { return function(); }
};

template<typename... A>
class CompatibleFunction<void(A...)>
{
public:
	using Ret = void;
	using Signature = Ret(A...);
	using Function = std::function<Signature>;
	using CompFuncType = CompatibleFunction<Signature>;
	using ArgsTuple = std::tuple<A...>;

protected:
	Function func_;

public:
	CompatibleFunction() = default;
	~CompatibleFunction() = default;

	//constructor
	template<typename F, typename = typename std::enable_if_t<IsCallable<F>>>
	CompatibleFunction(F func) noexcept { set(func); }

	template<typename F, typename O, typename = typename std::enable_if_t<IsCallable<F>>>
	CompatibleFunction(F func, O object) noexcept { set(memberCallback(func, object)); }

	CompatibleFunction(const CompFuncType& other) noexcept
		: func_(other.function()) {}
	template<typename Sig> CompatibleFunction(const CompatibleFunction<Sig>& other) noexcept
		{ set(other.function()); }

	//assignement
	template<typename F, typename = typename std::enable_if_t<IsCallable<F>>>
	CompFuncType& operator=(F func) noexcept { set(func); return *this; }

	CompFuncType& operator=(const CompFuncType& other) noexcept
		{ func_ = other.func_; return *this; }
	template<typename Sig> CompFuncType& operator=(const CompatibleFunction<Sig>& other) noexcept
		{ set(other.function()); return *this; }

	//set
	template<typename F>
	void set(F func) noexcept
	{
		using FuncTraits = FunctionTraits<F>;
		using RealArgsTuple = typename FuncTraits::ArgTuple;
		using MapType = detail::TupleMap<ArgsTuple, RealArgsTuple, void>;
		constexpr auto first = SeqGet<0, typename MapType::Seq, true>;

		static_assert(MapType::Seq::size() == FuncTraits::ArgSize, "Arguments not compatible");
		static_assert(first != std::size_t(-1), "Arguments not compatible");

		func_ = [=](A... args) -> Ret {
				MapType::map(func, std::forward<A>(args)...);
			};
	}

	//get
	Function function() const noexcept { return func_; }

	//call
	Ret call(A... args) const { func_(std::forward<A>(args)...); }
	Ret operator()(A... args) const { func_(std::forward<A>(args)...); }

	operator bool() const { return function(); }
};

//typedef CompFunc
template<typename S> using CompFunc = CompatibleFunction<S>;

}

#endif //heade guard
<|endoftext|>


<commit_before>/************************************************************************
	filename: 	CEGUIPropertyHelper.cpp
	created:	6/7/2004
	author:		Paul D Turner

	purpose:	Implementation of PropertyHelper methods
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://www.cegui.org.uk)
    Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "CEGUIPropertyHelper.h"
#include "CEGUIImagesetManager.h"
#include "CEGUIImageset.h"
#include "CEGUIExceptions.h"

#include <cstdio>

// Start of CEGUI namespace section
namespace CEGUI
{
float PropertyHelper::stringToFloat(const String& str)
{
	using namespace std;

	float val = 0;
	sscanf(str.c_str(), " %f", &val);

	return val;
}

uint PropertyHelper::stringToUint(const String& str)
{
	using namespace std;

	uint val = 0;
	sscanf(str.c_str(), " %u", &val);

	return val;
}

int PropertyHelper::stringToInt(const String& str)
{
	using namespace std;

	uint val = 0;
	sscanf(str.c_str(), " %d", &val);

	return val;
}

bool PropertyHelper::stringToBool(const String& str)
{
	if ((str == "True") || (str == "true"))
	{
		return true;
	}
	else
	{
		return false;
	}

}

Size PropertyHelper::stringToSize(const String& str)
{
	using namespace std;

	Size val(0,0);
	sscanf(str.c_str(), " w:%f h:%f", &val.d_width, &val.d_height);

	return val;
}

Point PropertyHelper::stringToPoint(const String& str)
{
	using namespace std;

	Point val(0,0) ;
	sscanf(str.c_str(), " x:%f y:%f", &val.d_x, &val.d_y);

	return val;
}

Rect PropertyHelper::stringToRect(const String& str)
{
	using namespace std;

	Rect val(0, 0, 0, 0);
	sscanf(str.c_str(), " l:%f t:%f r:%f b:%f", &val.d_left, &val.d_top, &val.d_right, &val.d_bottom);

	return val;
}

const Image* PropertyHelper::stringToImage(const String& str)
{
	using namespace std;

	char imageSet[128];
	char imageName[128];

	sscanf(str.c_str(), " set:%127s image:%127s", imageSet, imageName);

	const Image* image;

	try
	{
		image = &ImagesetManager::getSingleton().getImageset(imageSet)->getImage(imageName);
	}
	catch (UnknownObjectException)
	{
		image = 0;
	}

	return image;
}

UDim PropertyHelper::stringToUDim(const String& str)
{
	using namespace std;

	UDim ud;
	sscanf(str.c_str()," {%f,%f}", &ud.d_scale, &ud.d_offset);

	return ud;
}

UVector2 PropertyHelper::stringToUVector2(const String& str)
{
	using namespace std;

	UVector2 uv;
	sscanf(str.c_str(), " {{%f,%f},{%f,%f}}", &uv.d_x.d_scale,&uv.d_x.d_offset, &uv.d_y.d_scale,&uv.d_y.d_offset);

	return uv;
}

URect PropertyHelper::stringToURect(const String& str)
{
	using namespace std;

	URect ur;
	sscanf(
		str.c_str(),
		" {{%f,%f},{%f,%f},{%f,%f},{%f,%f}}",
		&ur.d_min.d_x.d_scale, &ur.d_min.d_x.d_offset,
		&ur.d_min.d_y.d_scale, &ur.d_min.d_y.d_offset,
		&ur.d_max.d_x.d_scale, &ur.d_max.d_x.d_offset,
		&ur.d_max.d_y.d_scale, &ur.d_max.d_y.d_offset
	);

	return ur;
}

String PropertyHelper::floatToString(float val)
{
	using namespace std;

	char buff[64];
	sprintf(buff, "%f", val);

	return String(buff);
}

String PropertyHelper::uintToString(uint val)
{
	using namespace std;

	char buff[64];
	sprintf(buff, "%u", val);

	return String(buff);
}

String PropertyHelper::intToString(int val)
{
	using namespace std;

	char buff[64];
	sprintf(buff, "%d", val);

	return String(buff);
}

String PropertyHelper::boolToString(bool val)
{
	if (val)
	{
		return String("True");
	}
	else
	{
		return String ("False");
	}

}

String PropertyHelper::sizeToString(const Size& val)
{
	using namespace std;

	char buff[128];
	sprintf(buff, "w:%f h:%f", val.d_width, val.d_height);

	return String(buff);
}

String PropertyHelper::pointToString(const Point& val)
{
	using namespace std;

	char buff[128];
	sprintf(buff, "x:%f y:%f", val.d_x, val.d_y);

	return String(buff);
}

String PropertyHelper::rectToString(const Rect& val)
{
	using namespace std;

	char buff[256];
	sprintf(buff, "l:%f t:%f r:%f b:%f", val.d_left, val.d_top, val.d_right, val.d_bottom);

	return String(buff);
}

String PropertyHelper::imageToString(const Image* const val)
{
	if (val)
	{
		return String("set:" + val->getImagesetName() + " image:" + val->getName());
	}

	return String("");
}

String PropertyHelper::udimToString(const UDim& val)
{
	using namespace std;

	char buff[128];
	sprintf(buff, "{%f,%f}", val.d_scale, val.d_offset);

	return String(buff);
}

String PropertyHelper::uvector2ToString(const UVector2& val)
{
	using namespace std;

	char buff[256];
	sprintf(buff, "{{%f,%f},{%f,%f}}", val.d_x.d_scale, val.d_x.d_offset, val.d_y.d_scale, val.d_y.d_offset);

	return String(buff);
}

String PropertyHelper::urectToString(const URect& val)
{
	using namespace std;

	char buff[512];
	sprintf(
		buff,
		"{{%f,%f},{%f,%f},{%f,%f},{%f,%f}}",
		val.d_min.d_x.d_scale,val.d_min.d_x.d_offset,
		val.d_min.d_y.d_scale,val.d_min.d_y.d_offset,
		val.d_max.d_x.d_scale,val.d_max.d_x.d_offset,
		val.d_max.d_y.d_scale,val.d_max.d_y.d_offset
	);

	return String(buff);
}

String PropertyHelper::colourToString(const colour& val)
{
	using namespace std;

	char buff[16];
	sprintf(buff, "%.8X", val.getARGB());

	return String(buff);
}

colour PropertyHelper::stringToColour(const String& str)
{
	using namespace std;

	argb_t val = 0xFF000000;
	sscanf(str.c_str(), " %8X", &val);

	return colour(val);

}

String PropertyHelper::colourRectToString(const ColourRect& val)
{
	using namespace std;

	char buff[64];
	sprintf(buff, "tl:%.8X tr:%.8X bl:%.8X br:%.8X", val.d_top_left.getARGB(), val.d_top_right.getARGB(), val.d_bottom_left.getARGB(), val.d_bottom_right.getARGB());

	return String(buff);
}

ColourRect PropertyHelper::stringToColourRect(const String& str)
{
	using namespace std;

	argb_t topLeft = 0xFF000000, topRight = 0xFF000000, bottomLeft = 0xFF000000, bottomRight = 0xFF000000;
	sscanf(str.c_str(), "tl:%8X tr:%8X bl:%8X br:%8X", &topLeft, &topRight, &bottomLeft, &bottomRight);

	return ColourRect(topLeft, topRight, bottomLeft, bottomRight);
}

} // End of  CEGUI namespace section
<commit_msg>Bug Fix: PropertyHelper::stringToImage was not handling empty string case.<commit_after>/************************************************************************
	filename: 	CEGUIPropertyHelper.cpp
	created:	6/7/2004
	author:		Paul D Turner

	purpose:	Implementation of PropertyHelper methods
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://www.cegui.org.uk)
    Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#include "CEGUIPropertyHelper.h"
#include "CEGUIImagesetManager.h"
#include "CEGUIImageset.h"
#include "CEGUIExceptions.h"

#include <cstdio>

// Start of CEGUI namespace section
namespace CEGUI
{
float PropertyHelper::stringToFloat(const String& str)
{
	using namespace std;

	float val = 0;
	sscanf(str.c_str(), " %f", &val);

	return val;
}

uint PropertyHelper::stringToUint(const String& str)
{
	using namespace std;

	uint val = 0;
	sscanf(str.c_str(), " %u", &val);

	return val;
}

int PropertyHelper::stringToInt(const String& str)
{
	using namespace std;

	uint val = 0;
	sscanf(str.c_str(), " %d", &val);

	return val;
}

bool PropertyHelper::stringToBool(const String& str)
{
	if ((str == "True") || (str == "true"))
	{
		return true;
	}
	else
	{
		return false;
	}

}

Size PropertyHelper::stringToSize(const String& str)
{
	using namespace std;

	Size val(0,0);
	sscanf(str.c_str(), " w:%f h:%f", &val.d_width, &val.d_height);

	return val;
}

Point PropertyHelper::stringToPoint(const String& str)
{
	using namespace std;

	Point val(0,0) ;
	sscanf(str.c_str(), " x:%f y:%f", &val.d_x, &val.d_y);

	return val;
}

Rect PropertyHelper::stringToRect(const String& str)
{
	using namespace std;

	Rect val(0, 0, 0, 0);
	sscanf(str.c_str(), " l:%f t:%f r:%f b:%f", &val.d_left, &val.d_top, &val.d_right, &val.d_bottom);

	return val;
}

const Image* PropertyHelper::stringToImage(const String& str)
{
	using namespace std;

    // handle empty string case
    if (str.empty())
        return 0;

	char imageSet[128];
	char imageName[128];

	sscanf(str.c_str(), " set:%127s image:%127s", imageSet, imageName);

	const Image* image;

	try
	{
		image = &ImagesetManager::getSingleton().getImageset(imageSet)->getImage(imageName);
	}
	catch (UnknownObjectException)
	{
		image = 0;
	}

	return image;
}

UDim PropertyHelper::stringToUDim(const String& str)
{
	using namespace std;

	UDim ud;
	sscanf(str.c_str()," {%f,%f}", &ud.d_scale, &ud.d_offset);

	return ud;
}

UVector2 PropertyHelper::stringToUVector2(const String& str)
{
	using namespace std;

	UVector2 uv;
	sscanf(str.c_str(), " {{%f,%f},{%f,%f}}", &uv.d_x.d_scale,&uv.d_x.d_offset, &uv.d_y.d_scale,&uv.d_y.d_offset);

	return uv;
}

URect PropertyHelper::stringToURect(const String& str)
{
	using namespace std;

	URect ur;
	sscanf(
		str.c_str(),
		" {{%f,%f},{%f,%f},{%f,%f},{%f,%f}}",
		&ur.d_min.d_x.d_scale, &ur.d_min.d_x.d_offset,
		&ur.d_min.d_y.d_scale, &ur.d_min.d_y.d_offset,
		&ur.d_max.d_x.d_scale, &ur.d_max.d_x.d_offset,
		&ur.d_max.d_y.d_scale, &ur.d_max.d_y.d_offset
	);

	return ur;
}

String PropertyHelper::floatToString(float val)
{
	using namespace std;

	char buff[64];
	sprintf(buff, "%f", val);

	return String(buff);
}

String PropertyHelper::uintToString(uint val)
{
	using namespace std;

	char buff[64];
	sprintf(buff, "%u", val);

	return String(buff);
}

String PropertyHelper::intToString(int val)
{
	using namespace std;

	char buff[64];
	sprintf(buff, "%d", val);

	return String(buff);
}

String PropertyHelper::boolToString(bool val)
{
	if (val)
	{
		return String("True");
	}
	else
	{
		return String ("False");
	}

}

String PropertyHelper::sizeToString(const Size& val)
{
	using namespace std;

	char buff[128];
	sprintf(buff, "w:%f h:%f", val.d_width, val.d_height);

	return String(buff);
}

String PropertyHelper::pointToString(const Point& val)
{
	using namespace std;

	char buff[128];
	sprintf(buff, "x:%f y:%f", val.d_x, val.d_y);

	return String(buff);
}

String PropertyHelper::rectToString(const Rect& val)
{
	using namespace std;

	char buff[256];
	sprintf(buff, "l:%f t:%f r:%f b:%f", val.d_left, val.d_top, val.d_right, val.d_bottom);

	return String(buff);
}

String PropertyHelper::imageToString(const Image* const val)
{
	if (val)
	{
		return String("set:" + val->getImagesetName() + " image:" + val->getName());
	}

	return String("");
}

String PropertyHelper::udimToString(const UDim& val)
{
	using namespace std;

	char buff[128];
	sprintf(buff, "{%f,%f}", val.d_scale, val.d_offset);

	return String(buff);
}

String PropertyHelper::uvector2ToString(const UVector2& val)
{
	using namespace std;

	char buff[256];
	sprintf(buff, "{{%f,%f},{%f,%f}}", val.d_x.d_scale, val.d_x.d_offset, val.d_y.d_scale, val.d_y.d_offset);

	return String(buff);
}

String PropertyHelper::urectToString(const URect& val)
{
	using namespace std;

	char buff[512];
	sprintf(
		buff,
		"{{%f,%f},{%f,%f},{%f,%f},{%f,%f}}",
		val.d_min.d_x.d_scale,val.d_min.d_x.d_offset,
		val.d_min.d_y.d_scale,val.d_min.d_y.d_offset,
		val.d_max.d_x.d_scale,val.d_max.d_x.d_offset,
		val.d_max.d_y.d_scale,val.d_max.d_y.d_offset
	);

	return String(buff);
}

String PropertyHelper::colourToString(const colour& val)
{
	using namespace std;

	char buff[16];
	sprintf(buff, "%.8X", val.getARGB());

	return String(buff);
}

colour PropertyHelper::stringToColour(const String& str)
{
	using namespace std;

	argb_t val = 0xFF000000;
	sscanf(str.c_str(), " %8X", &val);

	return colour(val);

}

String PropertyHelper::colourRectToString(const ColourRect& val)
{
	using namespace std;

	char buff[64];
	sprintf(buff, "tl:%.8X tr:%.8X bl:%.8X br:%.8X", val.d_top_left.getARGB(), val.d_top_right.getARGB(), val.d_bottom_left.getARGB(), val.d_bottom_right.getARGB());

	return String(buff);
}

ColourRect PropertyHelper::stringToColourRect(const String& str)
{
	using namespace std;

	argb_t topLeft = 0xFF000000, topRight = 0xFF000000, bottomLeft = 0xFF000000, bottomRight = 0xFF000000;
	sscanf(str.c_str(), "tl:%8X tr:%8X bl:%8X br:%8X", &topLeft, &topRight, &bottomLeft, &bottomRight);

	return ColourRect(topLeft, topRight, bottomLeft, bottomRight);
}

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>#include "CLSmith/CLOutputMgr.h"

#include <fstream>

#include "CLSmith/Globals.h"
#include "Function.h"
#include "OutputMgr.h"
#include "Type.h"
#include "VariableSelector.h"

namespace CLSmith {

const std::string kFileName = "CLProg.c";

CLOutputMgr::CLOutputMgr() : out_(kFileName.c_str()) {
}

void CLOutputMgr::OutputHeader(int argc, char *argv[], unsigned long seed) {
  // Redefine platform independent scalar C types to platform independent scalar
  // OpenCL types.
  std::ostream &out = get_main_out();
  out <<
      "#define int64_t long\n"
      "#define uint64_t ulong\n"
      "#define int_least64_t long\n"
      "#define uint_least64_t ulong\n"
      "#define int_fast64_t long\n"
      "#define uint_fast64_t ulong\n"
      "#define intmax_t long\n"
      "#define uintmax_t ulong\n"
      "#define int32_t int\n"
      "#define uint32_t uint\n"
      "#define int16_t short\n"
      "#define uint16_t ushort\n"
      "#define int8_t char\n"
      "#define uint8_t uchar\n"
      "\n"
      "#define INT64_MIN LONG_MIN\n"
      "#define INT64_MAX LONG_MAX\n"
      "#define INT32_MIN INT_MIN\n"
      "#define INT32_MAX INT_MAX\n"
      "#define INT16_MIN SHRT_MIN\n"
      "#define INT16_MAX SHRT_MAX\n"
      "#define INT8_MIN CHAR_MIN\n"
      "#define INT8_MAX CHAR_MAX\n"
      "#define UINT64_MIN ULONG_MIN\n"
      "#define UINT64_MAX ULONG_MAX\n"
      "#define UINT32_MIN UINT_MIN\n"
      "#define UINT32_MAX UINT_MAX\n"
      "#define UINT16_MIN USHRT_MIN\n"
      "#define UINT16_MAX USHRT_MAX\n"
      "#define UINT8_MIN UCHAR_MIN\n"
      "#define UINT8_MAX UCHAR_MAX\n"
      "\n"
      "#define transparent_crc(X, Y, Z) "
      "transparent_crc_(&crc64_context, X, Y, Z)\n"
      << std::endl;

  out << std::endl;
  out << "// Seed: " << seed << std::endl;
  out << std::endl;
  out << "#include \"CLSmith.h\"" << std::endl;
  out << std::endl;
}

void CLOutputMgr::Output() {
  std::ostream &out = get_main_out();
  OutputStructUnionDeclarations(out);

  Globals globals = Globals::CreateGlobals();
  globals.OutputStructDefinition(out);
  globals.ModifyGlobalVariableReferences();
  globals.AddGlobalStructToAllFunctions();

  OutputForwardDeclarations(out);
  OutputFunctions(out);
  OutputEntryFunction(globals);
}

std::ostream& CLOutputMgr::get_main_out() {
  return out_;
}

void CLOutputMgr::OutputEntryFunction(Globals& globals) {
  // Would ideally use the ExtensionMgr, but there is no way to set it to our
  // own custom made one (without modifying the code).
  std::ostream& out = get_main_out();
  out << "__kernel void entry(__global ulong *result) {" << std::endl;
  globals.OutputStructInit(out);

  output_tab(out, 1);
  out << "func_1(";
  globals.GetGlobalStructVar().Output(out);
  out << ");" << std::endl;

  // Handle hashing and outputting.
  output_tab(out, 1);
  out << "uint64_t crc64_context = 0xFFFFFFFFFFFFFFFFUL;" << std::endl;
  output_tab(out, 1);
  out << "int print_hash_value = 0;" << std::endl;
  HashGlobalVariables(out);
  output_tab(out, 1);
  out << "result[get_global_id(0)] = crc64_context ^ 0xFFFFFFFFFFFFFFFFUL;"
      << std::endl;

  output_tab(out, 1);
  out << "return 0;" << std::endl;
  out << "}" << std::endl;
}

}  // namespace CLSmith
<commit_msg>Remove return statement in kernel entry.<commit_after>#include "CLSmith/CLOutputMgr.h"

#include <fstream>

#include "CLSmith/Globals.h"
#include "Function.h"
#include "OutputMgr.h"
#include "Type.h"
#include "VariableSelector.h"

namespace CLSmith {

const std::string kFileName = "CLProg.c";

CLOutputMgr::CLOutputMgr() : out_(kFileName.c_str()) {
}

void CLOutputMgr::OutputHeader(int argc, char *argv[], unsigned long seed) {
  // Redefine platform independent scalar C types to platform independent scalar
  // OpenCL types.
  std::ostream &out = get_main_out();
  out <<
      "#define int64_t long\n"
      "#define uint64_t ulong\n"
      "#define int_least64_t long\n"
      "#define uint_least64_t ulong\n"
      "#define int_fast64_t long\n"
      "#define uint_fast64_t ulong\n"
      "#define intmax_t long\n"
      "#define uintmax_t ulong\n"
      "#define int32_t int\n"
      "#define uint32_t uint\n"
      "#define int16_t short\n"
      "#define uint16_t ushort\n"
      "#define int8_t char\n"
      "#define uint8_t uchar\n"
      "\n"
      "#define INT64_MIN LONG_MIN\n"
      "#define INT64_MAX LONG_MAX\n"
      "#define INT32_MIN INT_MIN\n"
      "#define INT32_MAX INT_MAX\n"
      "#define INT16_MIN SHRT_MIN\n"
      "#define INT16_MAX SHRT_MAX\n"
      "#define INT8_MIN CHAR_MIN\n"
      "#define INT8_MAX CHAR_MAX\n"
      "#define UINT64_MIN ULONG_MIN\n"
      "#define UINT64_MAX ULONG_MAX\n"
      "#define UINT32_MIN UINT_MIN\n"
      "#define UINT32_MAX UINT_MAX\n"
      "#define UINT16_MIN USHRT_MIN\n"
      "#define UINT16_MAX USHRT_MAX\n"
      "#define UINT8_MIN UCHAR_MIN\n"
      "#define UINT8_MAX UCHAR_MAX\n"
      "\n"
      "#define transparent_crc(X, Y, Z) "
      "transparent_crc_(&crc64_context, X, Y, Z)\n"
      << std::endl;

  out << std::endl;
  out << "// Seed: " << seed << std::endl;
  out << std::endl;
  out << "#include \"CLSmith.h\"" << std::endl;
  out << std::endl;
}

void CLOutputMgr::Output() {
  std::ostream &out = get_main_out();
  OutputStructUnionDeclarations(out);

  Globals globals = Globals::CreateGlobals();
  globals.OutputStructDefinition(out);
  globals.ModifyGlobalVariableReferences();
  globals.AddGlobalStructToAllFunctions();

  OutputForwardDeclarations(out);
  OutputFunctions(out);
  OutputEntryFunction(globals);
}

std::ostream& CLOutputMgr::get_main_out() {
  return out_;
}

void CLOutputMgr::OutputEntryFunction(Globals& globals) {
  // Would ideally use the ExtensionMgr, but there is no way to set it to our
  // own custom made one (without modifying the code).
  std::ostream& out = get_main_out();
  out << "__kernel void entry(__global ulong *result) {" << std::endl;
  globals.OutputStructInit(out);

  output_tab(out, 1);
  out << "func_1(";
  globals.GetGlobalStructVar().Output(out);
  out << ");" << std::endl;

  // Handle hashing and outputting.
  output_tab(out, 1);
  out << "uint64_t crc64_context = 0xFFFFFFFFFFFFFFFFUL;" << std::endl;
  output_tab(out, 1);
  out << "int print_hash_value = 0;" << std::endl;
  HashGlobalVariables(out);
  output_tab(out, 1);
  out << "result[get_global_id(0)] = crc64_context ^ 0xFFFFFFFFFFFFFFFFUL;"
      << std::endl;
  out << "}" << std::endl;
}

}  // namespace CLSmith
<|endoftext|>