<commit_before>#include <phypp.hpp>

const std::string egg_share_dir = file::directorize(EGG_SHARE_DIR);

void print_help();

int main(int argc, char* argv[]) {
    // Random seed to use to generate the noise
    uint_t tseed = 42;
    // Name of the FITS table containing the mock catalog
    std::string cat_file;
    // Name of the output FITS file "basename" in which to store the map
    // If out="file", then the map will be saved in "file-noise.fits"
    std::string out;
    // Name of the FITS file of the PSF
    std::string psf_file;
    // Name of the file from which to copy the astrometry
    std::string astro;
    // If not the above, specify the pixel scale
    double aspix = dnan;
    // The amplitude of the noise
    double rms = 1.0;

    // Filter the final map with beam smoothing
    bool beam_smoothed = false;
    // Beam smoothing uses the PSF by default, but you can choose an arbitrary Gaussian
    double smooth_fwhm = dnan;
    // Flag all the border pixels that are not well covered by NaN
    bool clip_borders = false;
    // Also build a coverage map ("file-cov.fits")
    bool make_cov = false;
    // Also build an error map ("file-err.fits")
    bool make_err = false;
    // Save the distance map (debug purposes, "file-dist.fits")
    bool save_dist = false;
    // Print some text on the console.
    bool verbose = false;

    if (argc < 2) {
        print_help();
        return 0;
    }

    read_args(argc, argv, arg_list(
        name(tseed, "seed"), out, name(psf_file, "psf"), astro, aspix, rms, beam_smoothed, smooth_fwhm,
        verbose, make_err, make_cov, clip_borders, save_dist, name(cat_file, "cat")
    ));

    if (out.empty() || psf_file.empty() || (astro.empty() && !is_finite(aspix))) {
        print_help();
        return 0;
    }

    if (!file::exists(psf_file)) {
        psf_file = egg_share_dir+"psfs/"+psf_file;
    }
    if (!file::exists(psf_file)) {
        error("the PSF file '"+psf_file+"' could not be found");

        note("available default PSFs:");
        vec1s tmps = file::list_files(egg_share_dir+"psfs/*.fits");
        inplace_sort(tmps);
        for (auto t : tmps) {
            print(" - ", t);
        }

        return 1;
    }

    auto seed = make_seed(tseed);

    struct {
        vec1d ra, dec;
    } cat;

    fits::read_table(cat_file, ftable(cat.ra, cat.dec));

    // Read the PSF
    if (verbose) note("reading and normalizing PSF...");

    vec2d psf;
    fits::read(psf_file, psf);

    // Center the PSF
    int_t hsize = std::max(psf.dims[0], psf.dims[1])/2;
    if (hsize > 40) hsize = 40;
    vec1i mid = mult_ids(psf, max_id(psf));
    psf = subregion(psf, {mid[0]-hsize, mid[1]-hsize, mid[0]+hsize, mid[1]+hsize});

    // Compute PSF FWHM
    double fwhm; {
        vec1u idok = where(psf > 0.2*max(psf));
        vec2d r2 = generate_img(psf.dims, [&](double ix, double iy) {
            return sqr(ix - hsize) + sqr(iy - hsize);
        });

        auto res = linfit(log(psf[idok]/max(psf)), 1, r2[idok]);
        if (res.params[0] >= 0) {
            error("could not estimate FWHM of the PSF");
            return 1;
        }

        fwhm = 2*sqrt(-log(2)/res.params[0]);

        if (verbose) note("FWHM=", fwhm, " pixels");
    }

    // Read astrometry
    if (verbose) note("configure astrometry...");

    vec2f noise;
    fits::header hdr; {
        if (astro.empty()) {
            // From parameters

            // Try a first naive projection where the first pixel is defined by the
            // most extreme galaxy in the corner of the field
            fits::make_wcs_header_params wcs_params;
            wcs_params.pixel_scale = aspix;
            wcs_params.pixel_ref_x = 1.0; wcs_params.pixel_ref_y = 1.0;
            wcs_params.sky_ref_ra = max(cat.ra); wcs_params.sky_ref_dec = min(cat.dec);

            if (!fits::make_wcs_header(wcs_params, hdr)) {
                error("could not make WCS header");
                return 1;
            }

            vec1d x, y;
            fits::ad2xy(fits::wcs(hdr), cat.ra, cat.dec, x, y);

            // Now, because of the spherical projection, some galaxies can have negative pixel
            // coordinates even though we picked the most extreme one in RA and Dec.
            // Figure out how negative this can be and adjust the reference pixel accordingly.
            // Also add an inset.
            double dx = 5*fwhm - (min(x) - 1);
            double dy = 5*fwhm - (min(y) - 1);
            wcs_params.pixel_ref_x += dx;
            wcs_params.pixel_ref_y += dy;

            if (!fits::make_wcs_header(wcs_params, hdr)) {
                error("could not make WCS header");
                return 1;
            }

            fits::ad2xy(fits::wcs(hdr), cat.ra, cat.dec, x, y);

            uint_t npx = ceil(max(x) + 5*fwhm);
            uint_t npy = ceil(max(y) + 5*fwhm);

            if (verbose) note("map will be ", npy, " x ", npx);

            noise.resize(npy, npx);
        } else {
            // From an existing FITS file
            fits::read(astro, noise, hdr);

            if (verbose) note("map will be ", noise.dims[0], " x ", noise.dims[1]);
        }
    }

    noise[_] = fnan;
    vec1u idin;

    if (clip_borders) {
        if (verbose) note("clipping field borders...");
        fits::wcs wcs(hdr);

        // Build convex hull around catalog sources
        vec1d sx, sy;
        fits::ad2xy(wcs, cat.ra, cat.dec, sx, sy);
        auto hull = build_convex_hull(sx, sy);

        // Compute distance of each pixel to the hull
        vec2d x = replicate(uindgen(noise.dims[1]), noise.dims[0]);
        vec2d y = transpose(replicate(uindgen(noise.dims[0]), noise.dims[1]));
        vec2d dist = convex_hull_distance(x, y, hull);

        if (save_dist) {
            fits::write(out+"-dist.fits", dist, hdr);
        }

        // Only use pixels that are more than 3 FWHM away from the border of the catalog
        idin = where(dist > 1.5*fwhm);
    } else {
        idin = uindgen(noise.size());
    }

    if (beam_smoothed) {
        if (verbose) note("estimate unfiltered noise level...");

        // Adjust the provided RMS to apply to the beam-smoothed map
        // Note: the map is not beam-smoothed yet, this will be done in 'egg-genmap'

        // Create the smoothing kernel
        vec2d kernel;
        if (is_finite(smooth_fwhm)) {
            kernel = gaussian_profile(psf.dims, smooth_fwhm/2.355);
        } else {
            kernel = psf;
        }

        // Remove zero elements
        vec1u idz = where(kernel < 1e-5*max(abs(kernel)));
        kernel[idz] = 0.0;

        // Normalize to unity to preserve flux
        vec2d cpsf = convolve2d(psf, kernel);
        kernel /= cpsf(hsize,hsize);

        // Create a random patch of noise and convolve it to see how it is affected
        vec2d rnd = randomn(seed, psf.dims[0]*4, psf.dims[1]*4);
        double orig_rms = stddev(rnd); // should be very close to 1
        rnd = convolve2d(rnd, kernel);
        double new_rms = stddev(rnd);

        // Correct the requested RMS so that it will apply to the final, beam-smoothed
        // map, but not the raw map with independent pixels
        rms *= orig_rms/new_rms;
    }

    if (verbose) note("generate noise...");
    noise[idin] = rms*randomn(seed, idin.size());

    // Save noise map
    if (verbose) note("write map to disk...");
    fits::write(out+"-noise.fits", noise, hdr);

    if (make_err) {
        // Build and save error map
        noise[idin] = rms;
        fits::write(out+"-err.fits", noise, hdr);
    }

    if (make_cov) {
        // Build and save coverage map
        noise[idin] = 1.0;
        fits::write(out+"-cov.fits", noise, hdr);
    }

    if (verbose) note("done.");

    return 0;
}

void print_help() {
    using namespace format;

    auto argdoc = [](const std::string& name, const std::string& type,
        const std::string& desc) {

        std::string header = " - "+name+" "+type;
        print(header);

        std::string indent = "    ";
        vec1s w = wrap(indent+desc, 80, indent);

        for (auto& s : w) {
            print(s);
        }
    };

    print("egg-gennoise v1.0rc1");
    print("usage: egg-gennoise cat=... out=... psf=... astro=... aspix=... rms=... [options]\n");

    print("List of mandatory parameters (no default value):");
    argdoc("cat", "[string]", "name of the file containing the mock catalog");
    argdoc("out", "[string]", "base name of the file(s) into which the map(s) will be "
        "saved. If out=\"file\", then the noise map will be saved in \"file-noise.fits\". "
        "Similarly for the other maps that the program can output (RMS map, coverage map).");
    argdoc("psf", "[string]", "name of the file containing the PSF. Note that, "
        "if the provided file does not exists, the program will also search in the list "
        "of the pre-built templates provided with EGG ("+egg_share_dir+
        "/psfs) for a file with the same name, and use it if it exists.");
    argdoc("astro", "[string]", "name of an existing FITS file from which the astrometry "
        "should be copied. The alternative is to specify the pixel scale (see below).");
    argdoc("aspix", "[double, arcsec/pixel]", "if 'astro' is not provided, one can also "
        "define the astrometry solution simply by giving the pixel scale. In this case "
        "the WCS data will be set so that the resulting image encompasses the whole "
        "input catalog.");
    argdoc("rms", "[double, map unit]", "specify the target pixel RMS of the image "
        "(pure Gaussian noise), as measured by the standard deviation of pixel values "
        "inside an aperture. This value will apply to the *final* map, i.e., after all "
        "post-processing (including in particular beam smoothing).");
    print("");

    print("List of options:");
    argdoc("beam_smoothed", "[flag]", "after the sources are placed on the map, convolve "
        "the map with the PSF (or an aribtrary Gaussian, see 'smooth_fwhm'). This is the "
        "standard procedure in the reduction of submillimeter images (default: false).");
    argdoc("smooth_fwhm", "[double]", "if 'beam_smoothed' is set, the default is to use "
        "the PSF itself to perform the convolution. This option allows choosing any other "
        "aribtrary Gaussian instead by specifying the FWHM manually (default: use PSF)");
    argdoc("clip_borders", "[flag]", "if set, pixels that are too close to the catalog "
        "border are flagged with NaN, since they lack contribution from nearby sources. "
        "This option ensures that the map statistics is uniform, and that no edge effects "
        "are present, but some galaxies will be clipped out.");
    argdoc("make_cov", "[flag]", "if set, save a coverage map (\"file-cov.fits\").");
    argdoc("make_err", "[flag]", "if set, save an RMS map (\"file-err.fits\").");
    argdoc("verbose", "[flag]", "print additional information in the standard output while "
        "the program is running (default: false)");
    print("");
}
<commit_msg>Made the command line argument more consistent<commit_after>#include <phypp.hpp>

const std::string egg_share_dir = file::directorize(EGG_SHARE_DIR);

void print_help();

int main(int argc, char* argv[]) {
    // Random seed to use to generate the noise
    uint_t tseed = 42;
    // Name of the FITS table containing the mock catalog
    std::string cat_file;
    // Name of the output FITS file "basename" in which to store the map
    // If out="file", then the map will be saved in "file-noise.fits"
    std::string out;
    // Name of the FITS file of the PSF
    std::string psf_file;
    // Name of the file from which to copy the astrometry
    std::string astro;
    // If not the above, specify the pixel scale
    double aspix = dnan;
    // The amplitude of the noise
    double rms = 1.0;

    // Filter the final map with beam smoothing
    bool beam_smoothed = false;
    // Beam smoothing uses the PSF by default, but you can choose an arbitrary Gaussian
    double smooth_fwhm = dnan;
    // Flag all the border pixels that are not well covered by NaN
    bool clip_borders = false;
    // Also build a coverage map ("file-cov.fits")
    bool make_cov = false;
    // Also build an error map ("file-err.fits")
    bool make_err = false;
    // Save the distance map (debug purposes, "file-dist.fits")
    bool save_dist = false;
    // Print some text on the console.
    bool verbose = false;

    if (argc < 2) {
        print_help();
        return 0;
    }

    read_args(argc, argv, arg_list(
        name(tseed, "seed"), out, name(psf_file, "psf"), astro, aspix, rms, beam_smoothed, smooth_fwhm,
        verbose, make_err, make_cov, clip_borders, save_dist, name(cat_file, "cat")
    ));

    if (out.empty() || psf_file.empty() || (astro.empty() && !is_finite(aspix))) {
        print_help();
        return 0;
    }

    std::string out_base = file::remove_extension(out);
    if (ends_width(out, "-noise")) {
        out_base = erase_end(out, "-noise");
    }

    if (!file::exists(psf_file)) {
        psf_file = egg_share_dir+"psfs/"+psf_file;
    }
    if (!file::exists(psf_file)) {
        error("the PSF file '"+psf_file+"' could not be found");

        note("available default PSFs:");
        vec1s tmps = file::list_files(egg_share_dir+"psfs/*.fits");
        inplace_sort(tmps);
        for (auto t : tmps) {
            print(" - ", t);
        }

        return 1;
    }

    auto seed = make_seed(tseed);

    struct {
        vec1d ra, dec;
    } cat;

    fits::read_table(cat_file, ftable(cat.ra, cat.dec));

    // Read the PSF
    if (verbose) note("reading and normalizing PSF...");

    vec2d psf;
    fits::read(psf_file, psf);

    // Center the PSF
    int_t hsize = std::max(psf.dims[0], psf.dims[1])/2;
    if (hsize > 40) hsize = 40;
    vec1i mid = mult_ids(psf, max_id(psf));
    psf = subregion(psf, {mid[0]-hsize, mid[1]-hsize, mid[0]+hsize, mid[1]+hsize});

    // Compute PSF FWHM
    double fwhm; {
        vec1u idok = where(psf > 0.2*max(psf));
        vec2d r2 = generate_img(psf.dims, [&](double ix, double iy) {
            return sqr(ix - hsize) + sqr(iy - hsize);
        });

        auto res = linfit(log(psf[idok]/max(psf)), 1, r2[idok]);
        if (res.params[0] >= 0) {
            error("could not estimate FWHM of the PSF");
            return 1;
        }

        fwhm = 2*sqrt(-log(2)/res.params[0]);

        if (verbose) note("FWHM=", fwhm, " pixels");
    }

    // Read astrometry
    if (verbose) note("configure astrometry...");

    vec2f noise;
    fits::header hdr; {
        if (astro.empty()) {
            // From parameters

            // Try a first naive projection where the first pixel is defined by the
            // most extreme galaxy in the corner of the field
            fits::make_wcs_header_params wcs_params;
            wcs_params.pixel_scale = aspix;
            wcs_params.pixel_ref_x = 1.0; wcs_params.pixel_ref_y = 1.0;
            wcs_params.sky_ref_ra = max(cat.ra); wcs_params.sky_ref_dec = min(cat.dec);

            if (!fits::make_wcs_header(wcs_params, hdr)) {
                error("could not make WCS header");
                return 1;
            }

            vec1d x, y;
            fits::ad2xy(fits::wcs(hdr), cat.ra, cat.dec, x, y);

            // Now, because of the spherical projection, some galaxies can have negative pixel
            // coordinates even though we picked the most extreme one in RA and Dec.
            // Figure out how negative this can be and adjust the reference pixel accordingly.
            // Also add an inset.
            double dx = 5*fwhm - (min(x) - 1);
            double dy = 5*fwhm - (min(y) - 1);
            wcs_params.pixel_ref_x += dx;
            wcs_params.pixel_ref_y += dy;

            if (!fits::make_wcs_header(wcs_params, hdr)) {
                error("could not make WCS header");
                return 1;
            }

            fits::ad2xy(fits::wcs(hdr), cat.ra, cat.dec, x, y);

            uint_t npx = ceil(max(x) + 5*fwhm);
            uint_t npy = ceil(max(y) + 5*fwhm);

            if (verbose) note("map will be ", npy, " x ", npx);

            noise.resize(npy, npx);
        } else {
            // From an existing FITS file
            fits::read(astro, noise, hdr);

            if (verbose) note("map will be ", noise.dims[0], " x ", noise.dims[1]);
        }
    }

    noise[_] = fnan;
    vec1u idin;

    if (clip_borders) {
        if (verbose) note("clipping field borders...");
        fits::wcs wcs(hdr);

        // Build convex hull around catalog sources
        vec1d sx, sy;
        fits::ad2xy(wcs, cat.ra, cat.dec, sx, sy);
        auto hull = build_convex_hull(sx, sy);

        // Compute distance of each pixel to the hull
        vec2d x = replicate(uindgen(noise.dims[1]), noise.dims[0]);
        vec2d y = transpose(replicate(uindgen(noise.dims[0]), noise.dims[1]));
        vec2d dist = convex_hull_distance(x, y, hull);

        if (save_dist) {
            fits::write(out_base+"-dist.fits", dist, hdr);
        }

        // Only use pixels that are more than 3 FWHM away from the border of the catalog
        idin = where(dist > 1.5*fwhm);
    } else {
        idin = uindgen(noise.size());
    }

    if (beam_smoothed) {
        if (verbose) note("estimate unfiltered noise level...");

        // Adjust the provided RMS to apply to the beam-smoothed map
        // Note: the map is not beam-smoothed yet, this will be done in 'egg-genmap'

        // Create the smoothing kernel
        vec2d kernel;
        if (is_finite(smooth_fwhm)) {
            kernel = gaussian_profile(psf.dims, smooth_fwhm/2.355);
        } else {
            kernel = psf;
        }

        // Remove zero elements
        vec1u idz = where(kernel < 1e-5*max(abs(kernel)));
        kernel[idz] = 0.0;

        // Normalize to unity to preserve flux
        vec2d cpsf = convolve2d(psf, kernel);
        kernel /= cpsf(hsize,hsize);

        // Create a random patch of noise and convolve it to see how it is affected
        vec2d rnd = randomn(seed, psf.dims[0]*4, psf.dims[1]*4);
        double orig_rms = stddev(rnd); // should be very close to 1
        rnd = convolve2d(rnd, kernel);
        double new_rms = stddev(rnd);

        // Correct the requested RMS so that it will apply to the final, beam-smoothed
        // map, but not the raw map with independent pixels
        rms *= orig_rms/new_rms;
    }

    if (verbose) note("generate noise...");
    noise[idin] = rms*randomn(seed, idin.size());

    // Save noise map
    if (verbose) note("write map to disk...");
    fits::write(out, noise, hdr);

    if (make_err) {
        // Build and save error map
        noise[idin] = rms;
        fits::write(out_base+"-err.fits", noise, hdr);
    }

    if (make_cov) {
        // Build and save coverage map
        noise[idin] = 1.0;
        fits::write(out_base+"-cov.fits", noise, hdr);
    }

    if (verbose) note("done.");

    return 0;
}

void print_help() {
    using namespace format;

    auto argdoc = [](const std::string& name, const std::string& type,
        const std::string& desc) {

        std::string header = " - "+name+" "+type;
        print(header);

        std::string indent = "    ";
        vec1s w = wrap(indent+desc, 80, indent);

        for (auto& s : w) {
            print(s);
        }
    };

    print("egg-gennoise v1.0rc1");
    print("usage: egg-gennoise cat=... out=... psf=... astro=... aspix=... rms=... [options]\n");

    print("List of mandatory parameters (no default value):");
    argdoc("cat", "[string]", "name of the file containing the mock catalog");
    argdoc("out", "[string]", "name of the file into which the noise map will be saved.");
    argdoc("psf", "[string]", "name of the file containing the PSF. Note that, "
        "if the provided file does not exists, the program will also search in the list "
        "of the pre-built templates provided with EGG ("+egg_share_dir+
        "/psfs) for a file with the same name, and use it if it exists.");
    argdoc("astro", "[string]", "name of an existing FITS file from which the astrometry "
        "should be copied. The alternative is to specify the pixel scale (see below).");
    argdoc("aspix", "[double, arcsec/pixel]", "if 'astro' is not provided, one can also "
        "define the astrometry solution simply by giving the pixel scale. In this case "
        "the WCS data will be set so that the resulting image encompasses the whole "
        "input catalog.");
    argdoc("rms", "[double, map unit]", "specify the target pixel RMS of the image "
        "(pure Gaussian noise), as measured by the standard deviation of pixel values "
        "inside an aperture. This value will apply to the *final* map, i.e., after all "
        "post-processing (including in particular beam smoothing).");
    print("");

    print("List of options:");
    argdoc("beam_smoothed", "[flag]", "after the sources are placed on the map, convolve "
        "the map with the PSF (or an aribtrary Gaussian, see 'smooth_fwhm'). This is the "
        "standard procedure in the reduction of submillimeter images (default: false).");
    argdoc("smooth_fwhm", "[double]", "if 'beam_smoothed' is set, the default is to use "
        "the PSF itself to perform the convolution. This option allows choosing any other "
        "aribtrary Gaussian instead by specifying the FWHM manually (default: use PSF)");
    argdoc("clip_borders", "[flag]", "if set, pixels that are too close to the catalog "
        "border are flagged with NaN, since they lack contribution from nearby sources. "
        "This option ensures that the map statistics is uniform, and that no edge effects "
        "are present, but some galaxies will be clipped out.");
    argdoc("make_cov", "[flag]", "if set, save a coverage map (\"[out]-cov.fits\").");
    argdoc("make_err", "[flag]", "if set, save an RMS map (\"[out]-err.fits\").");
    argdoc("verbose", "[flag]", "print additional information in the standard output while "
        "the program is running (default: false)");
    print("");
}
<|endoftext|>


<commit_before>/*
	Copyright 2022 Jordi SUBIRANA

	Permission is hereby granted, free of charge, to any person obtaining a copy of
	this software and associated documentation files (the "Software"), to deal in
	the Software without restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
	Software, and to permit persons to whom the Software is furnished to do so, subject
	to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
	INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
	PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
	CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
	OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef ATEMA_CORE_FLAGS_HPP
#define ATEMA_CORE_FLAGS_HPP

#include <type_traits>

#define ATEMA_DECLARE_FLAGS(at_type) \
	inline at::Flags<at_type> operator|(at_type a, at_type b) \
	{ \
		return at::Flags<at_type>(static_cast<int>(a) | static_cast<int>(b)); \
	} \
	inline at::Flags<at_type> operator&(at_type a, at_type b) \
	{ \
		return at::Flags<at_type>(static_cast<int>(a) & static_cast<int>(b)); \
	}

namespace at
{
	template <typename E>
	class Flags
	{
		static_assert(std::is_enum<E>::value, "Flags class requires an enum");

	public:
		Flags();
		Flags(int value);
		Flags(E value);
		Flags(const Flags<E>& value);
		~Flags();

		int getValue() const noexcept;

		operator bool() const noexcept;
		operator int() const noexcept;

		Flags operator|(E value) const noexcept;
		Flags operator|(const Flags<E>& value) const noexcept;
		Flags operator&(E value) const noexcept;
		Flags operator&(const Flags<E>& value) const noexcept;
		Flags& operator|=(E value) noexcept;
		Flags& operator|=(const Flags<E>& value) noexcept;
		Flags& operator&=(E value) noexcept;
		Flags& operator&=(const Flags<E>& value) noexcept;

		bool operator==(E value) const noexcept;
		bool operator==(const Flags<E>& value) const noexcept;
		bool operator!=(E value) const noexcept;
		bool operator!=(const Flags<E>& value) const noexcept;

	private:
		int m_value;
	};
}

#include <Atema/Core/Flags.inl>

#endif
<commit_msg>Core - Flags - std::hash overload<commit_after>/*
	Copyright 2022 Jordi SUBIRANA

	Permission is hereby granted, free of charge, to any person obtaining a copy of
	this software and associated documentation files (the "Software"), to deal in
	the Software without restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
	Software, and to permit persons to whom the Software is furnished to do so, subject
	to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
	INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
	PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
	CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
	OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef ATEMA_CORE_FLAGS_HPP
#define ATEMA_CORE_FLAGS_HPP

#include <type_traits>

#define ATEMA_DECLARE_FLAGS(at_type) \
	inline at::Flags<at_type> operator|(at_type a, at_type b) \
	{ \
		return at::Flags<at_type>(static_cast<int>(a) | static_cast<int>(b)); \
	} \
	inline at::Flags<at_type> operator&(at_type a, at_type b) \
	{ \
		return at::Flags<at_type>(static_cast<int>(a) & static_cast<int>(b)); \
	}

namespace at
{
	template <typename E>
	class Flags
	{
		static_assert(std::is_enum<E>::value, "Flags class requires an enum");

	public:
		Flags();
		Flags(int value);
		Flags(E value);
		Flags(const Flags<E>& value);
		~Flags();

		int getValue() const noexcept;

		operator bool() const noexcept;
		operator int() const noexcept;

		Flags operator|(E value) const noexcept;
		Flags operator|(const Flags<E>& value) const noexcept;
		Flags operator&(E value) const noexcept;
		Flags operator&(const Flags<E>& value) const noexcept;
		Flags& operator|=(E value) noexcept;
		Flags& operator|=(const Flags<E>& value) noexcept;
		Flags& operator&=(E value) noexcept;
		Flags& operator&=(const Flags<E>& value) noexcept;

		bool operator==(E value) const noexcept;
		bool operator==(const Flags<E>& value) const noexcept;
		bool operator!=(E value) const noexcept;
		bool operator!=(const Flags<E>& value) const noexcept;

	private:
		int m_value;
	};
}

// std::hash overload for flags
namespace std
{
	template <typename E>
	struct hash<at::Flags<E>>
	{
		size_t operator()(const at::Flags<E>& flags) const
		{
			return hash<int>(flags.getValue());
		}
	};
}

#include <Atema/Core/Flags.inl>

#endif
<|endoftext|>


<commit_before>/**
 * \file OgreOculusRenderer.hpp
 * \brief Initialize rendering for the rift with SDK post traitement (OpenGL)
 * \author A. Brainville (Ybalrid)
 */

#ifndef OGRE_OCULUS_RENDERER
#define OGRE_OCULUS_RENDERER

#include <glew.h>
#ifndef _WIN32 //NOT ON WINDOWS (Assuming Linux. Usinig X Window System as display server
#include <glxew.h> //Need GLX glew on X window system
#else
#include <wglew.h> //Need wgelw
#endif

//Oculus Rift Lib
#include <OVR.h>

#ifdef _WIN32
 #include <Windows.h>
#endif
#include <OVR_CAPI_GL.h>
/*
#include <OVR_CAPI.h>

//OpenGL CAPI OVR
#include <OVR_CAPI_GL.h>
#include <CAPI/GL/CAPI_GL_Util.h>
*/

//C++ SDL Includes
#include <iostream>
#include <sstream>

/*
//Oculus Rift Lib
#include <OVR.h>
//CAPI
#include <OVR_CAPI.h>

//OpenGL CAPI OVR
#include <OVR_CAPI_GL.h>
#include <CAPI/GL/CAPI_GL_Util.h>
*/
/*
#ifdef _WIN32
//Direct3D CAPI OVR. Forcing version 11
#define OVR_D3D_VERSION 11
#include <OVR_CAPI_D3D.h>
#include <CAPI/D3D1X/CAPI_D3D1X_Util.h>
#endif
*/

#ifndef _WIN32 //Assuming Linux  here. Any Unix based have that header includable
#include <unistd.h>
#endif

//Ogre
#include <Ogre.h>

//Texture manipulation
#include <OgreTexture.h>

//OpenGL Classes. Some low level access required
#include <RenderSystems/GL/OgreGLRenderSystem.h>
#include <RenderSystems/GL/OgreGLRenderTexture.h>
#include <RenderSystems/GL/OgreGLTexture.h>
#include <RenderSystems/GL/OgreGLTextureManager.h>

#ifdef _WIN32 //Possibility of adding D3D11 compatibility
#include <RenderSystems/Direct3D11/OgreD3D11RenderSystem.h>
#include <RenderSystems/Direct3D11/OgreD3D11Texture.h>
#include <RenderSystems/Direct3D11/OgreD3D11TextureManager.h>
#endif

//Accessing Oculus Rift through a class :
#include "OculusInterface.hpp"

//OS Specific build macro
#include "systemMacro.h"

using namespace std;
using namespace OVR;

struct OgrePose
{
	Ogre::Vector3 position;
	Ogre::Quaternion orientation;
};

class DLL OgreOculusRender
{
    public:
        OgreOculusRender(std::string windowName = "OgreOculusRender");
        ~OgreOculusRender();

		///Calculate, time and present a frame on the Rift display
		void RenderOneFrame();

		///Set the near Z clipping plane distance from the POV. Used to calculate Projections matricies
		void setCamerasNearClippingDistance(float distance);

		///Automatic initialization of the renderer.
        void initialize();

		///Start Oculus and Ogre libraries.
        void initLibraries();

		///Load the given 'resource.cfg' file. See Ogre Help for referene here.
        void loadReseourceFile(const char path[]);

		//Init all resource groups loaded on resource group manager.
        void initAllResources();

		///Get Configuration from ogre.cfg or display a Dialog. The Resolution and FullScreen settings will be ignored.
		void getOgreConfig();

		///Create the RenderWindow
        void createWindow();

		///Initialize the SceneManager for the aplication.
        void initScene();

		///Initialise the camera for Stereo Render
        void initCameras();

		///Initialise the RTT Rendering System. Create two textures, two viewports and bind cameras on them.
        void initRttRendering();

		///Init the Rift rendering. Configure Oculus SDK to use the two RTT textures created.
		///Overload of initOculus(); Permit to specify the Full Screen mode (or not)
		void initOculus(bool fullscreenState = true);

		///Set fullscreen. Value only used at window creation
		void setFullScreen(bool fs = true)
		{
			fullscreen = fs;
		}

		///Return true if fullscreen set.
		bool isFullscreen()
		{
			return fullscreen;
		}

		///Get the scene manager.
        Ogre::SceneManager* getSceneManager()
        {
            return smgr;
        }

		///Get the RenderWindow
        Ogre::RenderWindow* getWindow()
        {
            return window;
        }

		///Print various informations about the cameras
        void debugPrint()
        {
            for(int i(0); i < 2; i++)
            {
               cout << "cam " << i << " " << cams[i]->getPosition() << endl;
               cout << cams[i]->getOrientation() << endl;
            }
        }

		///Save content of 'left eye' RenderTexture to the specified file. Please use a valid extentsion of a format handeled by FreeImage
        void debugSaveToFile(const char path[])
        {
            if(rtts[0]) rtts[0]->writeContentsToFile(path);
        }

		///Get a node representing the camera. NOTE: Camera isn"t attached.
        Ogre::SceneNode* getCameraInformationNode()
        {
            return CameraNode;
        }

		///Get the timer
        Ogre::Timer* getTimer()
        {
            if(root)
                return root->getTimer();
            return NULL;
        }

		///Get time between frames
        float getUpdateTime()
        {
            return updateTime;
        }

		///Recenter rift to default position.
		void recenter()
		{
			ovrHmd_RecenterPose(oc->getHmd());
		}

		///Get to know if the Health and Safety warning dissmiss has be requested
		bool IsHsDissmissed()
		{
			return hsDissmissed;
		}

		///Request the dissmiss of the Health and Safety warning
		void dissmissHS();

    private:
        enum
        {
            left = 0,
            right = 1
        };

		bool fullscreen;

        ///Name of the Window
        string name;
        ///Ogre Root instance
        Ogre::Root* root;
		///Ogre Render Window
        Ogre::RenderWindow* window;
		///Ogre Scene Manager
        Ogre::SceneManager* smgr;
		///Stereoscopic camera array. Indexes are "left" and "right"
        Ogre::Camera* cams[2];

        Ogre::SceneNode* CameraNode;

		///Textures used for RTT Rendering. Indexes are "left" and "right"
		Ogre::RenderTexture* rtts[2];
		///Vewports on textures. Textures are separated. One vieport for each textures
        Ogre::Viewport* vpts[2];
		///The Z axis near clipping plane distance
        Ogre::Real nearClippingDistance;
		///Time betwenn frames in seconds
        float updateTime;

        ///Object for getting informations from the Oculus Rift
        OculusInterface* oc;
		///Fov descriptor for each eye. Indexes are "left" and "right"
        ovrFovPort EyeFov[2];
		///Render descriptor for each eye. Indexes are "left" and "right"
        ovrEyeRenderDesc EyeRenderDesc[2];
		///OpenGL Configuration
        ovrGLConfig cfg;
		///OpenGL Textures
        ovrGLTexture EyeTexture[2];
/*
#ifdef _WIN32
		///D3D11 Configuration
		ovrD3D11Config D3D11cfg;

		///D3D11 Textures
		ovrD3D11Texture D3D11EyeTexture[2];

		///On Windows only : true if RenderSystem Direct3D 11 is loaded instead of GL RenderSystem.
		bool direct3D;

#endif
		*/
		///Size of left eye texture
        ovrSizei texSizeL;
		///Size of right eye texture
        ovrSizei texSizeR;

		///Position of the camera.
        Ogre::Vector3 cameraPosition;
		///Orientation of the camera.
        Ogre::Quaternion cameraOrientation;

		bool hsDissmissed;

    public:
        Ogre::Vector3 lastOculusPosition;
        Ogre::Quaternion lastOculusOrientation;
		OgrePose returnPose;
};

#endif //OGRE_OCULUS_RENDERER
<commit_msg>remove useless headers. Keep everything D3D11 commented<commit_after>/**
 * \file OgreOculusRenderer.hpp
 * \brief Initialize rendering for the rift with SDK post traitement (OpenGL)
 * \author A. Brainville (Ybalrid)
 */

#ifndef OGRE_OCULUS_RENDERER
#define OGRE_OCULUS_RENDERER

#include <glew.h>
#ifndef _WIN32 //NOT ON WINDOWS (Assuming Linux. Usinig X Window System as display server
#include <glxew.h> //Need GLX glew on X window system
#else
#include <wglew.h> //Need wgelw
#endif

//Oculus Rift Lib
#include <OVR.h>

#ifdef _WIN32
#include <Windows.h>
#endif

#include <OVR_CAPI_GL.h>

//C++ SDL Includes
#include <iostream>
#include <sstream>

/*
#ifdef _WIN32
//Direct3D CAPI OVR. Forcing version 11
#define OVR_D3D_VERSION 11
#include <OVR_CAPI_D3D.h>
#include <CAPI/D3D1X/CAPI_D3D1X_Util.h>
#endif
*/

#ifndef _WIN32 //Assuming Linux  here. Any Unix based have that header includable
#include <unistd.h>
#endif

//Ogre
#include <Ogre.h>

//Texture manipulation
#include <OgreTexture.h>

//OpenGL Classes. Some low level access required
#include <RenderSystems/GL/OgreGLRenderSystem.h>
#include <RenderSystems/GL/OgreGLRenderTexture.h>
#include <RenderSystems/GL/OgreGLTexture.h>
#include <RenderSystems/GL/OgreGLTextureManager.h>

/*
#ifdef _WIN32 //Possibility of adding D3D11 compatibility
#include <RenderSystems/Direct3D11/OgreD3D11RenderSystem.h>
#include <RenderSystems/Direct3D11/OgreD3D11Texture.h>
#include <RenderSystems/Direct3D11/OgreD3D11TextureManager.h>
#endif
*/
//Accessing Oculus Rift through a class :
#include "OculusInterface.hpp"

//OS Specific build macro
#include "systemMacro.h"

using namespace std;
using namespace OVR;

struct OgrePose
{
	Ogre::Vector3 position;
	Ogre::Quaternion orientation;
};

class DLL OgreOculusRender
{
    public:
        OgreOculusRender(std::string windowName = "OgreOculusRender");
        ~OgreOculusRender();

		///Calculate, time and present a frame on the Rift display
		void RenderOneFrame();

		///Set the near Z clipping plane distance from the POV. Used to calculate Projections matricies
		void setCamerasNearClippingDistance(float distance);

		///Automatic initialization of the renderer.
        void initialize();

		///Start Oculus and Ogre libraries.
        void initLibraries();

		///Load the given 'resource.cfg' file. See Ogre Help for referene here.
        void loadReseourceFile(const char path[]);

		//Init all resource groups loaded on resource group manager.
        void initAllResources();

		///Get Configuration from ogre.cfg or display a Dialog. The Resolution and FullScreen settings will be ignored.
		void getOgreConfig();

		///Create the RenderWindow
        void createWindow();

		///Initialize the SceneManager for the aplication.
        void initScene();

		///Initialise the camera for Stereo Render
        void initCameras();

		///Initialise the RTT Rendering System. Create two textures, two viewports and bind cameras on them.
        void initRttRendering();

		///Init the Rift rendering. Configure Oculus SDK to use the two RTT textures created.
		///Overload of initOculus(); Permit to specify the Full Screen mode (or not)
		void initOculus(bool fullscreenState = true);

		///Set fullscreen. Value only used at window creation
		void setFullScreen(bool fs = true)
		{
			fullscreen = fs;
		}

		///Return true if fullscreen set.
		bool isFullscreen()
		{
			return fullscreen;
		}

		///Get the scene manager.
        Ogre::SceneManager* getSceneManager()
        {
            return smgr;
        }

		///Get the RenderWindow
        Ogre::RenderWindow* getWindow()
        {
            return window;
        }

		///Print various informations about the cameras
        void debugPrint()
        {
            for(int i(0); i < 2; i++)
            {
               cout << "cam " << i << " " << cams[i]->getPosition() << endl;
               cout << cams[i]->getOrientation() << endl;
            }
        }

		///Save content of 'left eye' RenderTexture to the specified file. Please use a valid extentsion of a format handeled by FreeImage
        void debugSaveToFile(const char path[])
        {
            if(rtts[0]) rtts[0]->writeContentsToFile(path);
        }

		///Get a node representing the camera. NOTE: Camera isn"t attached.
        Ogre::SceneNode* getCameraInformationNode()
        {
            return CameraNode;
        }

		///Get the timer
        Ogre::Timer* getTimer()
        {
            if(root)
                return root->getTimer();
            return NULL;
        }

		///Get time between frames
        float getUpdateTime()
        {
            return updateTime;
        }

		///Recenter rift to default position.
		void recenter()
		{
			ovrHmd_RecenterPose(oc->getHmd());
		}

		///Get to know if the Health and Safety warning dissmiss has be requested
		bool IsHsDissmissed()
		{
			return hsDissmissed;
		}

		///Request the dissmiss of the Health and Safety warning
		void dissmissHS();

    private:
        enum
        {
            left = 0,
            right = 1
        };

		bool fullscreen;

        ///Name of the Window
        string name;
        ///Ogre Root instance
        Ogre::Root* root;
		///Ogre Render Window
        Ogre::RenderWindow* window;
		///Ogre Scene Manager
        Ogre::SceneManager* smgr;
		///Stereoscopic camera array. Indexes are "left" and "right"
        Ogre::Camera* cams[2];

        Ogre::SceneNode* CameraNode;

		///Textures used for RTT Rendering. Indexes are "left" and "right"
		Ogre::RenderTexture* rtts[2];
		///Vewports on textures. Textures are separated. One vieport for each textures
        Ogre::Viewport* vpts[2];
		///The Z axis near clipping plane distance
        Ogre::Real nearClippingDistance;
		///Time betwenn frames in seconds
        float updateTime;

        ///Object for getting informations from the Oculus Rift
        OculusInterface* oc;
		///Fov descriptor for each eye. Indexes are "left" and "right"
        ovrFovPort EyeFov[2];
		///Render descriptor for each eye. Indexes are "left" and "right"
        ovrEyeRenderDesc EyeRenderDesc[2];
		///OpenGL Configuration
        ovrGLConfig cfg;
		///OpenGL Textures
        ovrGLTexture EyeTexture[2];
/*
#ifdef _WIN32
		///D3D11 Configuration
		ovrD3D11Config D3D11cfg;

		///D3D11 Textures
		ovrD3D11Texture D3D11EyeTexture[2];

		///On Windows only : true if RenderSystem Direct3D 11 is loaded instead of GL RenderSystem.
		bool direct3D;

#endif
		*/
		///Size of left eye texture
        ovrSizei texSizeL;
		///Size of right eye texture
        ovrSizei texSizeR;

		///Position of the camera.
        Ogre::Vector3 cameraPosition;
		///Orientation of the camera.
        Ogre::Quaternion cameraOrientation;

		bool hsDissmissed;

    public:
        Ogre::Vector3 lastOculusPosition;
        Ogre::Quaternion lastOculusOrientation;
		OgrePose returnPose;
};

#endif //OGRE_OCULUS_RENDERER
<|endoftext|>


<commit_before>/* ----------------------------------------------------------------------------
 * matrix.hpp
 *
 * Copyright (c) 2017 Yann Herklotz Grave <ymherklotz@gmail.com> -- MIT License
 * See file LICENSE for more details
 * ----------------------------------------------------------------------------
 */

/** \file matrix.hpp Templated matrix class
 *
 * Matrix
 * ======
 *
 * This is a very general matrix class that can then be inherited by
 * vectors and other similar data structures to minimize code
 * density.
 */

#ifndef YAGE_MATH_MATRIX_HPP
#define YAGE_MATH_MATRIX_HPP

#include <algorithm>
#include <exception>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

namespace yage {

template <int Rows, int Cols, class Type>
class Matrix;

/** @internal Namespace for internal details.
 *
 * Detail Namespace
 * ================
 *
 * This is the namespace used for implementation detail.
 */
namespace detail {

/** @internal Internal Row class used by the Matrix class to return the
 * internal data structure of the Matrix.
 *
 * Row
 * ===
 *
 * Internal Row class to return a value in the row of the matrix.
 */
template <int Rows, int Cols, class Type>
class Row {
private:
    Matrix<Rows, Cols, Type>* parent_;
    int index_;

public:
    Row<Rows, Cols, Type>(Matrix<Rows, Cols, Type>* parent, int index)
        : parent_(parent), index_(index) {}

    Type& operator[](int col) {
        // the index is the y-position of the element in the matrix
        return parent_->data_[index_ * Cols + col];
    }

    const Type& operator[](int col) const {
        return parent_->data_[index_ * Cols + col];
    }
};

}  // detail

/** Base Matrix class used by other similar classes.
 *
 * Matrix class
 * ============
 *
 * This is the base matrix class that can be used by all the other matrix
 * like data structures.
 */
template <int Rows = 4, int Cols = 4, class Type = double>
class Matrix {
    // friended with the row class so that it can access protected member data
    friend class detail::Row<Rows, Cols, Type>;

protected:
    /// Vector containing the data of the matrix
    std::vector<Type> data_;

public:
    /// Initializes the size of the data_ vector
    Matrix<Rows, Cols, Type>() : data_(Rows * Cols) {}
    Matrix<Rows, Cols, Type>(const std::vector<Type>& data) : data_(data) {}

    /// Returns the row size of the Matrix
    int rowSize() const { return Rows; }

    /// Returns the column size of the Matrixxs
    int colSize() const { return Cols; }

    /** Return the row specified row as a Matrix with only one row
   *
   * \param[in] row Row number to be returned
   *
   * Returns the row that is specified by the row variables.
   */
    Matrix<1, Cols, Type> getRow(int row) const {
        Matrix<1, Cols, Type> rowMatrix;
        for (int i = 0; i < Cols; ++i) {
            rowMatrix[0][i] = data_[row][i];
        }
        return rowMatrix;
    }

    // returns the column in a column matrix
    Matrix<Rows, 1, Type> getCol(int col) const {
        Matrix<Rows, 1, Type> colMatrix;
        for (int i = 0; i < Rows; ++i) {
            colMatrix[i][0] = data_[i][col];
        }
        return colMatrix;
    }

    // iterator support for begin
    typename std::vector<Type>::iterator begin() { return data_.begin(); }

    // iterator support for end
    typename std::vector<Type>::iterator end() { return data_.end(); }

    // prints out the matrix, but can also be implemented by other classes to
    // print data differently
    virtual std::string toString() const {
        std::stringstream ss;
        ss << '[';
        for (int i = 0; i < Rows - 1; ++i) {
            ss << '[';
            for (int j = 0; j < Cols - 1; ++j) {
                ss << data_[i * Cols + j] << ' ';
            }
            ss << data_[(Rows - 1) * Cols + Cols - 1] << "],";
        }
        ss << '[';
        for (int j = 0; j < Cols - 1; ++j) {
            ss << data_[(Rows - 1) * Cols + j] << ' ';
        }
        ss << data_[(Rows - 1) * Cols + Cols - 1] << "]]";
        return ss.str();
    }

    detail::Row<Rows, Cols, Type> operator[](int row) {
        return detail::Row<Rows, Cols, Type>(this, row);
    }

    detail::Row<Rows, Cols, Type> operator[](int row) const {
        // TODO got to fix this
        return detail::Row<Rows, Cols, Type>((Matrix<Rows, Cols, Type>*)this,
                                             row);
    }

    Matrix<Rows, Cols, Type>& operator+=(const Matrix<Rows, Cols, Type>& rhs) {
        std::vector<Type> out;
        out.reserve(data_.size());
        std::transform(data_.begin(), data_.end(), rhs.data_.begin(),
                       std::back_inserter(out),
                       [](Type a, Type b) { return a + b; });
        data_ = std::move(out);
        return *this;
    }

    Matrix<Rows, Cols, Type>& operator-=(const Matrix<Rows, Cols, Type>& rhs) {
        std::vector<Type> out;
        out.reserve(data_.size());
        std::transform(data_.begin(), data_.end(), rhs.begin(),
                       std::back_inserter(out),
                       [](Type a, Type b) { return a - b; });
        data_ = std::move(out);
        return *this;
    }
};

template <int M, int N, class T>
Matrix<M, N, T> operator+(Matrix<M, N, T> lhs, const Matrix<M, N, T>& rhs) {
    lhs += rhs;
    return lhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator-(Matrix<M, N, T> lhs, const Matrix<M, N, T>& rhs) {
    lhs -= rhs;
    return lhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator+(Matrix<M, N, T> lhs, const T& rhs) {
    for (auto& data : lhs) {
        data += rhs;
    }
    return lhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator+(const T& lhs, Matrix<M, N, T> rhs) {
    for (auto& data : rhs) {
        data += lhs;
    }
    return rhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator-(Matrix<M, N, T> lhs, const T& rhs) {
    for (auto& data : lhs) {
        data -= rhs;
    }
    return lhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator-(const T& lhs, Matrix<M, N, T> rhs) {
    for (auto& data : rhs) {
        data = lhs - data;
    }
    return rhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator*(Matrix<M, N, T> lhs, const T& rhs) {
    for (auto& data : lhs) {
        data *= rhs;
    }
    return lhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator*(const T& lhs, Matrix<M, N, T> rhs) {
    for (auto& data : rhs) {
        data *= lhs;
    }
    return rhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator/(Matrix<M, N, T> lhs, const T& rhs) {
    for (auto& data : lhs) {
        data /= rhs;
    }
    return lhs;
}

template <int M, int N, class T>
bool operator==(const Matrix<M, N, T>& lhs, const Matrix<M, N, T>& rhs) {
    for (int i = 0; i < M; ++i)
        for (int j = 0; j < N; ++j)
            if (lhs[i][j] != rhs[i][j]) return false;
    return true;
}

template <int M, int N, class T>
std::ostream& operator<<(std::ostream& os, const Matrix<M, N, T>& mat) {
    return os << mat.toString();
}

template <int Rows = 2, class Type = double>
class Vector : public Matrix<Rows, 1, Type> {
public:
    Vector<Rows, Type>() : Matrix<Rows, 1, Type>() {}
    Vector<Rows, Type>(const Matrix<Rows, 1, Type>& other)
        : Matrix<Rows, 1, Type>(other) {}
    Vector<Rows, Type>(const std::vector<Type>& data)
        : Matrix<Rows, 1, Type>(data) {}

    Type& operator[](int col) { return this->data_[col]; }

    const Type& operator[](int col) const { return this->data_[col]; }

    virtual std::string toString() const {
        std::stringstream ss;
        ss << "[";
        for (std::size_t i = 0; i < this->data_.size() - 1; ++i) {
            ss << this->data_[i] << " ";
        }
        ss << this->data_[this->data_.size() - 1] << "]";
        return ss.str();
    }
};

/** 2D Vector class.
 *
 * Two dimensional vector class.
 */
template <class Type = double>
class Vector2 : public Vector<2, Type> {
public:
    Vector2<Type>() : Vector<2, Type>() {}
    Vector2<Type>(const std::vector<Type>& data) : Vector<2, Type>(data) {}

    Vector2<Type>(Type x, Type y) {
        this->data_[0] = x;
        this->data_[1] = y;
    }

    Vector2<Type>(const Matrix<2, 1, Type>& other) : Vector<2, Type>(other) {}

    Type& x() { return this->data_[0]; }

    const Type& x() const { return this->data_[0]; }

    Type& y() { return this->data_[1]; }

    const Type& y() const { return this->data_[1]; }
};

/// Definition of a 2D vector.
typedef Vector2<double> Vector2d;

/** Namespace containing functions that operate on matrices. */
namespace matrix {

/** Transposes a matrix and returns the result
*
* \param[in] m input matrix.
*/
template <int M, int N, class T>
Matrix<N, M, T> transpose(const Matrix<M, N, T>& m) {
    Matrix<N, M, T> trans;
    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < N; ++j) {
            trans[j][i] = m[i][j];
        }
    }
    return trans;
}

/** Returns the dot product between two vectors
*
* \param[in] m1,m2 Input matrices.
*/
template <int R, class T>
T dot(const Matrix<R, 1, T>& m1, const Matrix<R, 1, T>& m2) {
    T sum = 0;
    for (int i = 0; i < R; ++i) {
        sum += m1[i][0] * m2[i][0];
    }
    return sum;
}

/** Multiplies two matrices together.
*
* \param[in] m1,m2 Matrix inputs
*
* Requires the two matrices to be compatible with multiplication.
*/
template <int M, int N, int P, int Q, class T>
Matrix<M, Q, T> multiply(const Matrix<M, N, T>& m1, const Matrix<P, Q, T>& m2) {
    if (N != P) {
        throw std::runtime_error(
            "Matrices don't have the right dimensions for multiplication");
    }

    Matrix<M, Q, T> res;

    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < Q; ++j) {
            res[i][j] = dot(transpose(m1.getRow(i)), m2.getCol(j));
        }
    }

    return res;
}

}  // matrix

}  // yage

#endif
<commit_msg>Highlight didn't work<commit_after>/* ----------------------------------------------------------------------------
 * matrix.hpp
 *
 * Copyright (c) 2017 Yann Herklotz Grave <ymherklotz@gmail.com> -- MIT License
 * See file LICENSE for more details
 * ----------------------------------------------------------------------------
 */

/** \file matrix.hpp Templated matrix class
 *
 * Matrix
 * ======
 *
 * This is a very general matrix class that can then be inherited by
 * vectors and other similar data structures to minimize code
 * density.
 */

#ifndef YAGE_MATH_MATRIX_HPP
#define YAGE_MATH_MATRIX_HPP

#include <algorithm>
#include <exception>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

namespace yage {

template <int Rows, int Cols, class Type>
class Matrix;

/** \internal Namespace for internal details.
 *
 * Detail Namespace
 * ================
 *
 * This is the namespace used for implementation detail.
 */
namespace detail {

/** \internal Internal Row class used by the Matrix class to return the
 * internal data structure of the Matrix.
 *
 * Row
 * ===
 *
 * Internal Row class to return a value in the row of the matrix.
 */
template <int Rows, int Cols, class Type>
class Row {
private:
    Matrix<Rows, Cols, Type>* parent_;
    int index_;

public:
    Row<Rows, Cols, Type>(Matrix<Rows, Cols, Type>* parent, int index)
        : parent_(parent), index_(index) {}

    Type& operator[](int col) {
        // the index is the y-position of the element in the matrix
        return parent_->data_[index_ * Cols + col];
    }

    const Type& operator[](int col) const {
        return parent_->data_[index_ * Cols + col];
    }
};

}  // detail

/** Base Matrix class used by other similar classes.
 *
 * Matrix class
 * ============
 *
 * This is the base matrix class that can be used by all the other matrix
 * like data structures.
 */
template <int Rows = 4, int Cols = 4, class Type = double>
class Matrix {
    // friended with the row class so that it can access protected member data
    friend class detail::Row<Rows, Cols, Type>;

protected:
    /// Vector containing the data of the matrix
    std::vector<Type> data_;

public:
    /// Initializes the size of the data_ vector
    Matrix<Rows, Cols, Type>() : data_(Rows * Cols) {}
    Matrix<Rows, Cols, Type>(const std::vector<Type>& data) : data_(data) {}

    /// Returns the row size of the Matrix
    int rowSize() const { return Rows; }

    /// Returns the column size of the Matrixxs
    int colSize() const { return Cols; }

    /** Return the row specified row as a Matrix with only one row
   *
   * \param[in] row Row number to be returned
   *
   * Returns the row that is specified by the row variables.
   */
    Matrix<1, Cols, Type> getRow(int row) const {
        Matrix<1, Cols, Type> rowMatrix;
        for (int i = 0; i < Cols; ++i) {
            rowMatrix[0][i] = data_[row][i];
        }
        return rowMatrix;
    }

    // returns the column in a column matrix
    Matrix<Rows, 1, Type> getCol(int col) const {
        Matrix<Rows, 1, Type> colMatrix;
        for (int i = 0; i < Rows; ++i) {
            colMatrix[i][0] = data_[i][col];
        }
        return colMatrix;
    }

    // iterator support for begin
    typename std::vector<Type>::iterator begin() { return data_.begin(); }

    // iterator support for end
    typename std::vector<Type>::iterator end() { return data_.end(); }

    // prints out the matrix, but can also be implemented by other classes to
    // print data differently
    virtual std::string toString() const {
        std::stringstream ss;
        ss << '[';
        for (int i = 0; i < Rows - 1; ++i) {
            ss << '[';
            for (int j = 0; j < Cols - 1; ++j) {
                ss << data_[i * Cols + j] << ' ';
            }
            ss << data_[(Rows - 1) * Cols + Cols - 1] << "],";
        }
        ss << '[';
        for (int j = 0; j < Cols - 1; ++j) {
            ss << data_[(Rows - 1) * Cols + j] << ' ';
        }
        ss << data_[(Rows - 1) * Cols + Cols - 1] << "]]";
        return ss.str();
    }

    detail::Row<Rows, Cols, Type> operator[](int row) {
        return detail::Row<Rows, Cols, Type>(this, row);
    }

    detail::Row<Rows, Cols, Type> operator[](int row) const {
        // TODO got to fix this
        return detail::Row<Rows, Cols, Type>((Matrix<Rows, Cols, Type>*)this,
                                             row);
    }

    Matrix<Rows, Cols, Type>& operator+=(const Matrix<Rows, Cols, Type>& rhs) {
        std::vector<Type> out;
        out.reserve(data_.size());
        std::transform(data_.begin(), data_.end(), rhs.data_.begin(),
                       std::back_inserter(out),
                       [](Type a, Type b) { return a + b; });
        data_ = std::move(out);
        return *this;
    }

    Matrix<Rows, Cols, Type>& operator-=(const Matrix<Rows, Cols, Type>& rhs) {
        std::vector<Type> out;
        out.reserve(data_.size());
        std::transform(data_.begin(), data_.end(), rhs.begin(),
                       std::back_inserter(out),
                       [](Type a, Type b) { return a - b; });
        data_ = std::move(out);
        return *this;
    }
};

template <int M, int N, class T>
Matrix<M, N, T> operator+(Matrix<M, N, T> lhs, const Matrix<M, N, T>& rhs) {
    lhs += rhs;
    return lhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator-(Matrix<M, N, T> lhs, const Matrix<M, N, T>& rhs) {
    lhs -= rhs;
    return lhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator+(Matrix<M, N, T> lhs, const T& rhs) {
    for (auto& data : lhs) {
        data += rhs;
    }
    return lhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator+(const T& lhs, Matrix<M, N, T> rhs) {
    for (auto& data : rhs) {
        data += lhs;
    }
    return rhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator-(Matrix<M, N, T> lhs, const T& rhs) {
    for (auto& data : lhs) {
        data -= rhs;
    }
    return lhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator-(const T& lhs, Matrix<M, N, T> rhs) {
    for (auto& data : rhs) {
        data = lhs - data;
    }
    return rhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator*(Matrix<M, N, T> lhs, const T& rhs) {
    for (auto& data : lhs) {
        data *= rhs;
    }
    return lhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator*(const T& lhs, Matrix<M, N, T> rhs) {
    for (auto& data : rhs) {
        data *= lhs;
    }
    return rhs;
}

template <int M, int N, class T>
Matrix<M, N, T> operator/(Matrix<M, N, T> lhs, const T& rhs) {
    for (auto& data : lhs) {
        data /= rhs;
    }
    return lhs;
}

template <int M, int N, class T>
bool operator==(const Matrix<M, N, T>& lhs, const Matrix<M, N, T>& rhs) {
    for (int i = 0; i < M; ++i)
        for (int j = 0; j < N; ++j)
            if (lhs[i][j] != rhs[i][j]) return false;
    return true;
}

template <int M, int N, class T>
std::ostream& operator<<(std::ostream& os, const Matrix<M, N, T>& mat) {
    return os << mat.toString();
}

template <int Rows = 2, class Type = double>
class Vector : public Matrix<Rows, 1, Type> {
public:
    Vector<Rows, Type>() : Matrix<Rows, 1, Type>() {}
    Vector<Rows, Type>(const Matrix<Rows, 1, Type>& other)
        : Matrix<Rows, 1, Type>(other) {}
    Vector<Rows, Type>(const std::vector<Type>& data)
        : Matrix<Rows, 1, Type>(data) {}

    Type& operator[](int col) { return this->data_[col]; }

    const Type& operator[](int col) const { return this->data_[col]; }

    virtual std::string toString() const {
        std::stringstream ss;
        ss << "[";
        for (std::size_t i = 0; i < this->data_.size() - 1; ++i) {
            ss << this->data_[i] << " ";
        }
        ss << this->data_[this->data_.size() - 1] << "]";
        return ss.str();
    }
};

/** 2D Vector class.
 *
 * Two dimensional vector class.
 */
template <class Type = double>
class Vector2 : public Vector<2, Type> {
public:
    Vector2<Type>() : Vector<2, Type>() {}
    Vector2<Type>(const std::vector<Type>& data) : Vector<2, Type>(data) {}

    Vector2<Type>(Type x, Type y) {
        this->data_[0] = x;
        this->data_[1] = y;
    }

    Vector2<Type>(const Matrix<2, 1, Type>& other) : Vector<2, Type>(other) {}

    Type& x() { return this->data_[0]; }

    const Type& x() const { return this->data_[0]; }

    Type& y() { return this->data_[1]; }

    const Type& y() const { return this->data_[1]; }
};

/// Definition of a 2D vector.
typedef Vector2<double> Vector2d;

/** Namespace containing functions that operate on matrices. */
namespace matrix {

/** Transposes a matrix and returns the result
*
* \param[in] m input matrix.
*/
template <int M, int N, class T>
Matrix<N, M, T> transpose(const Matrix<M, N, T>& m) {
    Matrix<N, M, T> trans;
    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < N; ++j) {
            trans[j][i] = m[i][j];
        }
    }
    return trans;
}

/** Returns the dot product between two vectors
*
* \param[in] m1,m2 Input matrices.
*/
template <int R, class T>
T dot(const Matrix<R, 1, T>& m1, const Matrix<R, 1, T>& m2) {
    T sum = 0;
    for (int i = 0; i < R; ++i) {
        sum += m1[i][0] * m2[i][0];
    }
    return sum;
}

/** Multiplies two matrices together.
*
* \param[in] m1,m2 Matrix inputs
*
* Requires the two matrices to be compatible with multiplication.
*/
template <int M, int N, int P, int Q, class T>
Matrix<M, Q, T> multiply(const Matrix<M, N, T>& m1, const Matrix<P, Q, T>& m2) {
    if (N != P) {
        throw std::runtime_error(
            "Matrices don't have the right dimensions for multiplication");
    }

    Matrix<M, Q, T> res;

    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < Q; ++j) {
            res[i][j] = dot(transpose(m1.getRow(i)), m2.getCol(j));
        }
    }

    return res;
}

}  // matrix

}  // yage

#endif
<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015-2016 Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade 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 3 of the
License, or (at your option) any later version.

Abaclade 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 Abaclade. If
not, see <http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_NET_TCP_HXX
#define _ABACLADE_NET_TCP_HXX

#ifndef _ABACLADE_HXX
   #error "Please #include <abaclade.hxx> before this file"
#endif
#ifdef ABC_CXX_PRAGMA_ONCE
   #pragma once
#endif

#include <abaclade/io/binary.hxx>
#include <abaclade/net/ip.hxx>

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

namespace abc { namespace net {

//! Transmission Control Protocol-related classes and facilities.
namespace tcp {}

}} //namespace abc::net

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

namespace abc { namespace net { namespace tcp {

//! Initialized TCP connection.
class ABACLADE_SYM connection : public noncopyable {
public:
   /*! Constructor.

   @param fd
      Connected socket.
   @param addrRemote
      Address of the remote peer.
   @param portRemote
      Port of the remote peer.
   */
   connection(io::filedesc fd, ip::address && addrRemote, ip::port && portRemote);

   //! Destructor.
   ~connection();

   /*! Returns the address of the remote peer.

   @return
      IP address.
   */
   ip::address const & address() const {
      return m_addrRemote;
   }

   /*! Returns a binary reader/writer object representing the socket, to receive data from the
   remote peer.

   @return
      Reader/writer for the connection’s socket.
   */
   _std::shared_ptr<io::binary::file_readwriter> const & socket() {
      return m_bfrw;
   }

private:
   //! Reader/writer for the connection’s socket.
   _std::shared_ptr<io::binary::file_readwriter> m_bfrw;
   //! Address of the remote peer.
   ip::address m_addrRemote;
   //! Port of the remote peer.
   ip::port m_portRemote;
};

}}} //namespace abc::net::tcp

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

namespace abc { namespace net { namespace tcp {

/*! Attaches a coroutine scheduler to the current thread, and performs and necessary initialization
required for the current thread to run coroutines.
*/
class ABACLADE_SYM server : public noncopyable {
public:
   /*! Constructor.

   @param addr
      Address to bind to.
   @param port
      Port to listen for connections on.
   @param cBacklog
      Count of established connections that will be allowed to queue until the server is able to
      accept them.
   */
   server(ip::address const & addr, ip::port const & port, unsigned cBacklog = 5);

   //! Destructor.
   ~server();

   /*! Accepts and returns a connection from a client.

   @return
      New client connection.
   */
   _std::shared_ptr<connection> accept();

private:
   /*! Creates a socket for the server.

   @param ipversion
      IP version.
   @return
      New server socket.
   */
   static io::filedesc create_socket(ip::version ipversion);

private:
   //! Server socket bound to the TCP port.
   io::filedesc m_fdSocket;
   //! IP version.
   ip::version m_ipversion;
};

}}} //namespace abc::net::tcp

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

#endif //ifndef _ABACLADE_NET_TCP_HXX
<commit_msg>Rename abc::net::tcp::connection::address() and port() to remote_*()<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015-2016 Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade 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 3 of the
License, or (at your option) any later version.

Abaclade 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 Abaclade. If
not, see <http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_NET_TCP_HXX
#define _ABACLADE_NET_TCP_HXX

#ifndef _ABACLADE_HXX
   #error "Please #include <abaclade.hxx> before this file"
#endif
#ifdef ABC_CXX_PRAGMA_ONCE
   #pragma once
#endif

#include <abaclade/io/binary.hxx>
#include <abaclade/net/ip.hxx>

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

namespace abc { namespace net {

//! Transmission Control Protocol-related classes and facilities.
namespace tcp {}

}} //namespace abc::net

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

namespace abc { namespace net { namespace tcp {

//! Initialized TCP connection.
class ABACLADE_SYM connection : public noncopyable {
public:
   /*! Constructor.

   @param fd
      Connected socket.
   @param addrRemote
      Address of the remote peer.
   @param portRemote
      Port of the remote peer.
   */
   connection(io::filedesc fd, ip::address && addrRemote, ip::port && portRemote);

   //! Destructor.
   ~connection();

   /*! Returns the address of the remote peer.

   @return
      IP address.
   */
   ip::address const & remote_address() const {
      return m_addrRemote;
   }

   /*! Returns the port the remote peer is using.

   @return
      Port.
   */
   ip::port const & remote_port() const {
      return m_portRemote;
   }

   /*! Returns a binary reader/writer object representing the socket, to receive data from the
   remote peer.

   @return
      Reader/writer for the connection’s socket.
   */
   _std::shared_ptr<io::binary::file_readwriter> const & socket() {
      return m_bfrw;
   }

private:
   //! Reader/writer for the connection’s socket.
   _std::shared_ptr<io::binary::file_readwriter> m_bfrw;
   //! Address of the remote peer.
   ip::address m_addrRemote;
   //! Port of the remote peer.
   ip::port m_portRemote;
};

}}} //namespace abc::net::tcp

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

namespace abc { namespace net { namespace tcp {

/*! Attaches a coroutine scheduler to the current thread, and performs and necessary initialization
required for the current thread to run coroutines.
*/
class ABACLADE_SYM server : public noncopyable {
public:
   /*! Constructor.

   @param addr
      Address to bind to.
   @param port
      Port to listen for connections on.
   @param cBacklog
      Count of established connections that will be allowed to queue until the server is able to
      accept them.
   */
   server(ip::address const & addr, ip::port const & port, unsigned cBacklog = 5);

   //! Destructor.
   ~server();

   /*! Accepts and returns a connection from a client.

   @return
      New client connection.
   */
   _std::shared_ptr<connection> accept();

private:
   /*! Creates a socket for the server.

   @param ipversion
      IP version.
   @return
      New server socket.
   */
   static io::filedesc create_socket(ip::version ipversion);

private:
   //! Server socket bound to the TCP port.
   io::filedesc m_fdSocket;
   //! IP version.
   ip::version m_ipversion;
};

}}} //namespace abc::net::tcp

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

#endif //ifndef _ABACLADE_NET_TCP_HXX
<|endoftext|>


<commit_before>#ifndef CTRE__RETURN_TYPE__HPP
#define CTRE__RETURN_TYPE__HPP

#include "id.hpp"
#include <type_traits>
#include <tuple>
#include <string_view>

namespace ctre {

struct not_matched_tag_t { };

static constexpr inline auto not_matched = not_matched_tag_t{};

template <size_t Id, typename Name = void> struct captured_content {
	template <typename Iterator> struct storage {
		Iterator _begin{};
		Iterator _end{};
		bool _matched{false};

		using name = Name;

		constexpr CTRE_FORCE_INLINE storage() noexcept {}

		constexpr CTRE_FORCE_INLINE void matched() noexcept {
			_matched = true;
		}
		constexpr CTRE_FORCE_INLINE void unmatch() noexcept {
			_matched = false;
		}
		constexpr CTRE_FORCE_INLINE void set_start(Iterator pos) noexcept {
			_begin = pos;
		}
		constexpr CTRE_FORCE_INLINE storage & set_end(Iterator pos) noexcept {
			_end = pos;
			return *this;
		}
		constexpr CTRE_FORCE_INLINE Iterator get_end() const noexcept {
			return _end;
		}

		constexpr auto begin() const noexcept {
			return _begin;
		}
		constexpr auto end() const noexcept {
			return _end;
		}

		constexpr CTRE_FORCE_INLINE operator bool() const noexcept {
			return _matched;
		}

		constexpr CTRE_FORCE_INLINE auto to_view() const noexcept {
			return std::string_view{_begin, static_cast<size_t>(std::distance(_begin, _end))};
		}

		constexpr operator std::string_view() const noexcept {
			return to_view();
		}

		constexpr CTRE_FORCE_INLINE static size_t get_id() noexcept {
			return Id;
		}
	};
};

struct capture_not_exists_tag { };

static constexpr inline auto capture_not_exists = capture_not_exists_tag{};

template <typename... Captures> struct captures;

template <typename Head, typename... Tail> struct captures<Head, Tail...>: captures<Tail...> {
	Head head;
	constexpr CTRE_FORCE_INLINE captures() noexcept { }
	template <size_t id> CTRE_FORCE_INLINE static constexpr bool exists() noexcept {
		if constexpr (id == Head::get_id()) {
			return true;
		} else {
			return captures<Tail...>::template exists<id>();
		}
	}
	template <typename Name> CTRE_FORCE_INLINE static constexpr bool exists() noexcept {
		if constexpr (std::is_same_v<Name, typename Head::name>) {
			return true;
		} else {
			return captures<Tail...>::template exists<Name>();
		}
	}
	template <size_t id> CTRE_FORCE_INLINE constexpr auto & select() noexcept {
		if constexpr (id == Head::get_id()) {
			return head;
		} else {
			return captures<Tail...>::template select<id>();
		}
	}
	template <typename Name> CTRE_FORCE_INLINE constexpr auto & select() noexcept {
		if constexpr (std::is_same_v<Name, typename Head::name>) {
			return head;
		} else {
			return captures<Tail...>::template select<Name>();
		}
	}
	template <size_t id> CTRE_FORCE_INLINE constexpr auto & select() const noexcept {
		if constexpr (id == Head::get_id()) {
			return head;
		} else {
			return captures<Tail...>::template select<id>();
		}
	}
	template <typename Name> CTRE_FORCE_INLINE constexpr auto & select() const noexcept {
		if constexpr (std::is_same_v<Name, typename Head::name>) {
			return head;
		} else {
			return captures<Tail...>::template select<Name>();
		}
	}
};

template <> struct captures<> {
	constexpr CTRE_FORCE_INLINE captures() noexcept { }
	template <size_t> CTRE_FORCE_INLINE static constexpr bool exists() noexcept {
		return false;
	}
	template <typename> CTRE_FORCE_INLINE static constexpr bool exists() noexcept {
		return false;
	}
	template <size_t> CTRE_FORCE_INLINE constexpr auto & select() const noexcept {
		return capture_not_exists;
	}
	template <typename> CTRE_FORCE_INLINE constexpr auto & select() const noexcept {
		return capture_not_exists;
	}
};

template <typename Iterator, typename... Captures> struct regex_results {
	captures<captured_content<0>::template storage<Iterator>, typename Captures::template storage<Iterator>...> _captures;

	constexpr CTRE_FORCE_INLINE regex_results() noexcept { }
	constexpr CTRE_FORCE_INLINE regex_results(not_matched_tag_t) noexcept { }

	// special constructor for deducting
	constexpr CTRE_FORCE_INLINE regex_results(Iterator, ctll::list<Captures...>) noexcept { }

	template <size_t Id, typename = std::enable_if_t<decltype(_captures)::template exists<Id>()>> CTRE_FORCE_INLINE constexpr auto get() const noexcept {
		return _captures.template select<Id>();
	}
	template <typename Name, typename = std::enable_if_t<decltype(_captures)::template exists<Name>()>> CTRE_FORCE_INLINE constexpr auto get() const noexcept {
		return _captures.template select<Name>();
	}
	static constexpr size_t size() noexcept {
		return sizeof...(Captures) + 1;
	}
	constexpr CTRE_FORCE_INLINE regex_results & matched() noexcept {
		_captures.template select<0>().matched();
		return *this;
	}
	constexpr CTRE_FORCE_INLINE regex_results & unmatch() noexcept {
		_captures.template select<0>().unmatch();
		return *this;
	}
	constexpr CTRE_FORCE_INLINE operator bool() const noexcept {
		return bool(_captures.template select<0>());
	}

	constexpr operator std::string_view() const noexcept {
		return to_view();
	}

	constexpr auto to_view() const noexcept {
		return _captures.template select<0>().to_view();
	}

	constexpr CTRE_FORCE_INLINE regex_results & set_start_mark(Iterator pos) noexcept {
		_captures.template select<0>().set_start(pos);
		return *this;
	}
	constexpr CTRE_FORCE_INLINE regex_results & set_end_mark(Iterator pos) noexcept {
		_captures.template select<0>().set_end(pos);
		return *this;
	}
	constexpr CTRE_FORCE_INLINE Iterator get_end_position() const noexcept {
		return _captures.template select<0>().get_end();
	}
	template <size_t Id> CTRE_FORCE_INLINE constexpr regex_results & start_capture(Iterator pos) noexcept {
		_captures.template select<Id>().set_start(pos);
		return *this;
	}
	template <size_t Id> CTRE_FORCE_INLINE constexpr regex_results & end_capture(Iterator pos) noexcept {
		_captures.template select<Id>().set_end(pos).matched();
		return *this;
	}
};

template <typename Iterator, typename... Captures> regex_results(Iterator, ctll::list<Captures...>) -> regex_results<Iterator, Captures...>;

}

// support for structured bindings

namespace std {
	template <typename... Captures> class tuple_size<ctre::regex_results<Captures...>> : public std::integral_constant<size_t, ctre::regex_results<Captures...>::size()> { };

	template <size_t N, typename... Captures> class tuple_element<N, ctre::regex_results<Captures...>> {
	public:
		using type = decltype(
			std::declval<const ctre::regex_results<Captures...> &>().template get<N>()
		);
	};
}

#endif<commit_msg>support for wide string_views in msvc<commit_after>#ifndef CTRE__RETURN_TYPE__HPP
#define CTRE__RETURN_TYPE__HPP

#include "id.hpp"
#include <type_traits>
#include <tuple>
#include <string_view>

namespace ctre {

struct not_matched_tag_t { };

static constexpr inline auto not_matched = not_matched_tag_t{};

template <size_t Id, typename Name = void> struct captured_content {
	template <typename Iterator> struct storage {
		Iterator _begin{};
		Iterator _end{};

		using char_type = typename std::iterator_traits<Iterator>::value_type;

		bool _matched{false};

		using name = Name;

		constexpr CTRE_FORCE_INLINE storage() noexcept {}

		constexpr CTRE_FORCE_INLINE void matched() noexcept {
			_matched = true;
		}
		constexpr CTRE_FORCE_INLINE void unmatch() noexcept {
			_matched = false;
		}
		constexpr CTRE_FORCE_INLINE void set_start(Iterator pos) noexcept {
			_begin = pos;
		}
		constexpr CTRE_FORCE_INLINE storage & set_end(Iterator pos) noexcept {
			_end = pos;
			return *this;
		}
		constexpr CTRE_FORCE_INLINE Iterator get_end() const noexcept {
			return _end;
		}

		constexpr auto begin() const noexcept {
			return _begin;
		}
		constexpr auto end() const noexcept {
			return _end;
		}

		constexpr CTRE_FORCE_INLINE operator bool() const noexcept {
			return _matched;
		}

		constexpr CTRE_FORCE_INLINE auto to_view() const noexcept {
			return std::basic_string_view<char_type>(&*_begin, static_cast<size_t>(std::distance(_begin, _end)));
		}

		template <typename U = char_type>
		constexpr operator std::basic_string_view<U>() const noexcept {
			return to_view();
		}

		constexpr CTRE_FORCE_INLINE static size_t get_id() noexcept {
			return Id;
		}
	};
};

struct capture_not_exists_tag { };

static constexpr inline auto capture_not_exists = capture_not_exists_tag{};

template <typename... Captures> struct captures;

template <typename Head, typename... Tail> struct captures<Head, Tail...>: captures<Tail...> {
	Head head;
	constexpr CTRE_FORCE_INLINE captures() noexcept { }
	template <size_t id> CTRE_FORCE_INLINE static constexpr bool exists() noexcept {
		if constexpr (id == Head::get_id()) {
			return true;
		} else {
			return captures<Tail...>::template exists<id>();
		}
	}
	template <typename Name> CTRE_FORCE_INLINE static constexpr bool exists() noexcept {
		if constexpr (std::is_same_v<Name, typename Head::name>) {
			return true;
		} else {
			return captures<Tail...>::template exists<Name>();
		}
	}
	template <size_t id> CTRE_FORCE_INLINE constexpr auto & select() noexcept {
		if constexpr (id == Head::get_id()) {
			return head;
		} else {
			return captures<Tail...>::template select<id>();
		}
	}
	template <typename Name> CTRE_FORCE_INLINE constexpr auto & select() noexcept {
		if constexpr (std::is_same_v<Name, typename Head::name>) {
			return head;
		} else {
			return captures<Tail...>::template select<Name>();
		}
	}
	template <size_t id> CTRE_FORCE_INLINE constexpr auto & select() const noexcept {
		if constexpr (id == Head::get_id()) {
			return head;
		} else {
			return captures<Tail...>::template select<id>();
		}
	}
	template <typename Name> CTRE_FORCE_INLINE constexpr auto & select() const noexcept {
		if constexpr (std::is_same_v<Name, typename Head::name>) {
			return head;
		} else {
			return captures<Tail...>::template select<Name>();
		}
	}
};

template <> struct captures<> {
	constexpr CTRE_FORCE_INLINE captures() noexcept { }
	template <size_t> CTRE_FORCE_INLINE static constexpr bool exists() noexcept {
		return false;
	}
	template <typename> CTRE_FORCE_INLINE static constexpr bool exists() noexcept {
		return false;
	}
	template <size_t> CTRE_FORCE_INLINE constexpr auto & select() const noexcept {
		return capture_not_exists;
	}
	template <typename> CTRE_FORCE_INLINE constexpr auto & select() const noexcept {
		return capture_not_exists;
	}
};

template <typename Iterator, typename... Captures> struct regex_results {
	using char_type = typename std::iterator_traits<Iterator>::value_type;

	captures<captured_content<0>::template storage<Iterator>, typename Captures::template storage<Iterator>...> _captures;

	constexpr CTRE_FORCE_INLINE regex_results() noexcept { }
	constexpr CTRE_FORCE_INLINE regex_results(not_matched_tag_t) noexcept { }

	// special constructor for deducting
	constexpr CTRE_FORCE_INLINE regex_results(Iterator, ctll::list<Captures...>) noexcept { }

	template <size_t Id, typename = std::enable_if_t<decltype(_captures)::template exists<Id>()>> CTRE_FORCE_INLINE constexpr auto get() const noexcept {
		return _captures.template select<Id>();
	}
	template <typename Name, typename = std::enable_if_t<decltype(_captures)::template exists<Name>()>> CTRE_FORCE_INLINE constexpr auto get() const noexcept {
		return _captures.template select<Name>();
	}
	static constexpr size_t size() noexcept {
		return sizeof...(Captures) + 1;
	}
	constexpr CTRE_FORCE_INLINE regex_results & matched() noexcept {
		_captures.template select<0>().matched();
		return *this;
	}
	constexpr CTRE_FORCE_INLINE regex_results & unmatch() noexcept {
		_captures.template select<0>().unmatch();
		return *this;
	}
	constexpr CTRE_FORCE_INLINE operator bool() const noexcept {
		return bool(_captures.template select<0>());
	}

	template <typename U = char_type>
	constexpr operator std::basic_string_view<U>() const noexcept {
		return to_view();
	}

	constexpr auto to_view() const noexcept {
		return _captures.template select<0>().to_view();
	}

	constexpr CTRE_FORCE_INLINE regex_results & set_start_mark(Iterator pos) noexcept {
		_captures.template select<0>().set_start(pos);
		return *this;
	}
	constexpr CTRE_FORCE_INLINE regex_results & set_end_mark(Iterator pos) noexcept {
		_captures.template select<0>().set_end(pos);
		return *this;
	}
	constexpr CTRE_FORCE_INLINE Iterator get_end_position() const noexcept {
		return _captures.template select<0>().get_end();
	}
	template <size_t Id> CTRE_FORCE_INLINE constexpr regex_results & start_capture(Iterator pos) noexcept {
		_captures.template select<Id>().set_start(pos);
		return *this;
	}
	template <size_t Id> CTRE_FORCE_INLINE constexpr regex_results & end_capture(Iterator pos) noexcept {
		_captures.template select<Id>().set_end(pos).matched();
		return *this;
	}
};

template <typename Iterator, typename... Captures> regex_results(Iterator, ctll::list<Captures...>) -> regex_results<Iterator, Captures...>;

}

// support for structured bindings

namespace std {
	template <typename... Captures> class tuple_size<ctre::regex_results<Captures...>> : public std::integral_constant<size_t, ctre::regex_results<Captures...>::size()> { };

	template <size_t N, typename... Captures> class tuple_element<N, ctre::regex_results<Captures...>> {
	public:
		using type = decltype(
			std::declval<const ctre::regex_results<Captures...> &>().template get<N>()
		);
	};
}

#endif<|endoftext|>


<commit_before>#include <log-manager/LogServerRequest.h>
#include <log-manager/LogServerConnection.h>

#include <util/ClockTimer.h>
#include <common/Utilities.h>

#include <boost/uuid/random_generator.hpp>

using namespace sf1r;

void t_RpcLogServer();
void t_RpcLogServerTestData();

int main(int argc, char* argv[])
{
    try
    {
        t_RpcLogServerTestData();
        //t_RpcLogServer();
    }
    catch(std::exception& e)
    {
        std::cout<<e.what()<<std::endl;
    }

    return 0;
}

void t_RpcLogServer()
{
    LogServerConnection& conn = LogServerConnection::instance();
    conn.init("localhost", 18811);

//    UUID2DocIdList uuidReqData;
//    uuidReqData.uuid_ = "123456789abcdef0";
//    conn.asynRequest(LogServerRequest::METHOD_UPDATE_UUID, uuidReqData);
//
//    UpdateUUIDRequest uuidReq;
//    uuidReq.param_.uuid_ = "123456789abcdef1";
//    conn.asynRequest(uuidReq);

    UpdateUUIDRequest uuidReq;
    uuidReq.param_.docidList_.push_back(1111);
    uuidReq.param_.docidList_.push_back(2222);
    uuidReq.param_.docidList_.push_back(3333);

    izenelib::util::ClockTimer t;
    boost::uuids::random_generator random_gen;
    for (int i = 0; i < 1; i++)
    {
        for (int j = 0; j < 0x1000000; j++)
        {
            boost::uuids::uuid uuid = random_gen();
            uuidReq.param_.uuid_ = *reinterpret_cast<uint128_t *>(&uuid);
            conn.asynRequest(uuidReq);
        }
    }
    conn.flushRequests();
    std::cout << "time elapsed for inserting " << t.elapsed() << std::endl;
}

void t_RpcLogServerTestData()
{
    LogServerConnection& conn = LogServerConnection::instance();
    conn.init("localhost", 18811);

    UpdateUUIDRequest uuidReq;

    uuidReq.param_.docidList_.push_back(1111);
    uuidReq.param_.docidList_.push_back(2222);
    uuidReq.param_.docidList_.push_back(3333);
    uuidReq.param_.uuid_ = Utilities::hexStringToUint128("143c7d31702e4facb57b84d35205ae60");
    conn.asynRequest(uuidReq);

    uuidReq.param_.docidList_.push_back(4444);
    uuidReq.param_.docidList_.push_back(5555);
    uuidReq.param_.uuid_ = Utilities::hexStringToUint128("cda5545ab3f44e819b852d25b0416997");
    conn.asynRequest(uuidReq);

    conn.flushRequests();
}

//{"collection":"b5ma","resource":{"session_id":"","USERID":"","ITEMID":"143c7d31702e4facb57b84d35205ae60","is_recommend_item":"false"},"header":{"controller":"recommend","action":"visit_item"}}
//{"collection":"b5ma","resource":{"session_id":"","USERID":"","ITEMID":"e2ecc3000e2742049eba2a73ebda8013","is_recommend_item":"false"},"header":{"controller":"recommend","action":"visit_item"}}
//{"resource":{"DOCID":"cda5545ab3f44e819b852d25b0416997"},"collection":"b5ma","header":{"controller":"documents","action":"visit"}}
//{"resource":{"DOCID":"027b6fed167c46fea83c73c6f6e209a2"},"collection":"b5ma","header":{"controller":"documents","action":"visit"}}
//{"collection":"b5ma","resource":{"USERID":"","items":[{"ITEMID":"6bf634c51b4f4772bb52224b94c17af9","price":19,"quantity":1}]},"header":{"controller":"recommend","action":"purchase_item"}}
//{"collection":"b5ma","resource":{"USERID":"","items":[{"ITEMID":"623999b623b24be5b12531fda9e1439f","price":11880,"quantity":1}]},"header":{"controller":"recommend","action":"purchase_item"}}
//{"collection":"b5ma","resource":{"USERID":"","items":[{"ITEMID":"eb1ba5f4a5584a66806d74cb6a321932","price":1088,"quantity":1},{"ITEMID":"dcdce290b73d467baa44755cce035c79","price":65,"quantity":1}]},"header":{"controller":"recommend","action":"purchase_item"}}

<commit_msg>test data for log server<commit_after>#include <log-manager/LogServerRequest.h>
#include <log-manager/LogServerConnection.h>

#include <util/ClockTimer.h>
#include <common/Utilities.h>

#include <boost/uuid/random_generator.hpp>

using namespace sf1r;

void t_RpcLogServer();
void t_RpcLogServerCreateTestData();
void t_RpcLogServerUpdateTestData();

int main(int argc, char* argv[])
{
    try
    {
        if (argc > 1 && strcmp(argv[1], "-ct") == 0)
        {
            t_RpcLogServerCreateTestData();
        }
        else if (argc > 1 && strcmp(argv[1], "-ut") == 0)
        {
            t_RpcLogServerUpdateTestData();
        }
        else
        {
            t_RpcLogServer();
        }

    }
    catch(std::exception& e)
    {
        std::cout<<e.what()<<std::endl;
    }

    return 0;
}

void t_RpcLogServer()
{
    LogServerConnection& conn = LogServerConnection::instance();
    conn.init("localhost", 18811);

    UpdateUUIDRequest uuidReq;
    uuidReq.param_.docidList_.push_back(1111);
    uuidReq.param_.docidList_.push_back(2222);
    uuidReq.param_.docidList_.push_back(3333);

    izenelib::util::ClockTimer t;
    boost::uuids::random_generator random_gen;
    for (int i = 0; i < 1; i++)
    {
        for (int j = 0; j < 0x1000000; j++)
        {
            boost::uuids::uuid uuid = random_gen();
            uuidReq.param_.uuid_ = *reinterpret_cast<uint128_t *>(&uuid);
            conn.asynRequest(uuidReq);
        }
    }
    conn.flushRequests();
    std::cout << "time elapsed for inserting " << t.elapsed() << std::endl;
}

void t_RpcLogServerCreateTestData()
{
    LogServerConnection& conn = LogServerConnection::instance();
    conn.init("localhost", 18811);

    UpdateUUIDRequest uuidReq;

    uuidReq.param_.docidList_.push_back(11110);
    uuidReq.param_.docidList_.push_back(22220);
    uuidReq.param_.docidList_.push_back(33330);
    uuidReq.param_.uuid_ = Utilities::uuidToUint128("143c7d31-702e-4fac-b57b-84d35205ae60");
    conn.asynRequest(uuidReq);
    std::cout << "sent rpc request: " << uuidReq.param_.toString() << std::endl;

    uuidReq.param_.docidList_.clear();
    uuidReq.param_.docidList_.push_back(44440);
    uuidReq.param_.docidList_.push_back(55550);
    uuidReq.param_.uuid_ = Utilities::uuidToUint128("cda5545a-b3f4-4e81-9b85-2d25b0416997");
    conn.asynRequest(uuidReq);
    std::cout << "sent rpc request: " << uuidReq.param_.toString() << std::endl;

    uuidReq.param_.docidList_.clear();
    uuidReq.param_.docidList_.push_back(66660);
    uuidReq.param_.docidList_.push_back(77770);
    uuidReq.param_.uuid_ = Utilities::uuidToUint128("eb1ba5f4-a558-4a66-806d-74cb6a321932");
    conn.asynRequest(uuidReq);
    std::cout << "sent rpc request: " << uuidReq.param_.toString() << std::endl;

    uuidReq.param_.docidList_.clear();
    uuidReq.param_.docidList_.push_back(88880);
    uuidReq.param_.docidList_.push_back(99990);
    uuidReq.param_.uuid_ = Utilities::uuidToUint128("dcdce290-b73d-467b-aa44-755cce035c79");
    conn.asynRequest(uuidReq);
    std::cout << "sent rpc request: " << uuidReq.param_.toString() << std::endl;

    conn.flushRequests();

    // =====> cclog after uuid generated

    // {"collection":"b5ma","resource":{"session_id":"","USERID":"","ITEMID":"143c7d31-702e-4fac-b57b-84d35205ae60","is_recommend_item":"false"},"header":{"controller":"recommend","action":"visit_item"}}

    // {"resource":{"DOCID":"cda5545a-b3f4-4e81-9b85-2d25b0416997"},"collection":"b5ma","header":{"controller":"documents","action":"visit"}}

    // {"collection":"b5ma","resource":{"USERID":"","items":[{"ITEMID":"eb1ba5f4-a558-4a66-806d-74cb6a321932","price":1088,"quantity":1},{"ITEMID":"dcdce290-b73d-467b-aa44-755cce035c79","price":65,"quantity":1}]},"header":{"controller":"recommend","action":"purchase_item"}}
}

void t_RpcLogServerUpdateTestData()
{
    LogServerConnection& conn = LogServerConnection::instance();
    conn.init("localhost", 18811);

    UpdateUUIDRequest uuidReq;

    uuidReq.param_.docidList_.push_back(11110);
    uuidReq.param_.docidList_.push_back(22220);
    uuidReq.param_.uuid_ = Utilities::uuidToUint128("cc1e948d-ebf2-4a25-bf58-cb0c25ee65c1");
    conn.asynRequest(uuidReq);
    std::cout << "sent rpc request: " << uuidReq.param_.toString() << std::endl;

    uuidReq.param_.docidList_.clear();
    uuidReq.param_.docidList_.push_back(33330); //
    uuidReq.param_.docidList_.push_back(44440);
    uuidReq.param_.docidList_.push_back(55550);
    uuidReq.param_.uuid_ = Utilities::uuidToUint128("366f5977-aa73-412f-83f3-66fbe06a6b40");
    conn.asynRequest(uuidReq);
    std::cout << "sent rpc request: " << uuidReq.param_.toString() << std::endl;

    uuidReq.param_.docidList_.clear();
    uuidReq.param_.docidList_.push_back(66660);
    uuidReq.param_.docidList_.push_back(77770);
    uuidReq.param_.uuid_ = Utilities::uuidToUint128("6d5f82db-0ef2-4d5f-8b54-cdc29e97e5b1");
    conn.asynRequest(uuidReq);
    std::cout << "sent rpc request: " << uuidReq.param_.toString() << std::endl;

    uuidReq.param_.docidList_.clear();
    uuidReq.param_.docidList_.push_back(88880);
    uuidReq.param_.docidList_.push_back(99990);
    uuidReq.param_.uuid_ = Utilities::uuidToUint128("4857bcda-22e4-4a87-964d-17ffcf024d16");
    conn.asynRequest(uuidReq);
    std::cout << "sent rpc request: " << uuidReq.param_.toString() << std::endl;

    conn.flushRequests();

    // =====> update cclog (by driver log server) after uuid updated

    // {"collection":"b5ma","resource":{"session_id":"","USERID":"","ITEMID":"cc1e948d-ebf2-4a25-bf58-cb0c25ee65c1","is_recommend_item":"false"},"header":{"controller":"recommend","action":"visit_item"}}
    // {"collection":"b5ma","resource":{"session_id":"","USERID":"","ITEMID":"366f5977-aa73-412f-83f3-66fbe06a6b40","is_recommend_item":"false"},"header":{"controller":"recommend","action":"visit_item"}}

    // {"resource":{"DOCID":"366f5977-aa73-412f-83f3-66fbe06a6b40"},"collection":"b5ma","header":{"controller":"documents","action":"visit"}}

    // {"collection":"b5ma","resource":{"USERID":"","items":[{"ITEMID":"6d5f82db-0ef2-4d5f-8b54-cdc29e97e5b1","price":1088,"quantity":1},{"ITEMID":"4857bcda-22e4-4a87-964d-17ffcf024d16","price":65,"quantity":1}]},"header":{"controller":"recommend","action":"purchase_item"}}
}

<|endoftext|>


<commit_before>/**
 * This file defines the `event` class.
 */

#ifndef D2_SANDBOX_EVENT_HPP
#define D2_SANDBOX_EVENT_HPP

#include <d2/sandbox/parameter.hpp>

#include <boost/mpl/remove.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
#include <boost/proto/proto.hpp>

namespace d2 {
namespace sandbox {

namespace event_detail {
D2_PARAMETER_TEMPLATE_KEYWORD(scope)
namespace tag { struct members; }

namespace members_detail { struct not_used; }

#define D2_MAX_EVENT_MEMBERS 10
template <
    BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(
        D2_MAX_EVENT_MEMBERS, typename A, members_detail::not_used
    )
>
struct members
    : parameter_template_keyword<
        tag::members,
        boost::mpl::remove<
            boost::mpl::vector<BOOST_PP_ENUM_PARAMS(D2_MAX_EVENT_MEMBERS, A)>,
            members_detail::not_used
        >
    >
{ };

typedef boost::parameter::parameters<
            boost::parameter::required<tag::scope>
        ,   boost::parameter::optional<tag::members>
        > signature;

template <typename Args>
class event_impl {
    template <typename Tag, typename Default = boost::parameter::void_>
    struct arg
        : parameter_value_type<Args, Tag, Default>
    { };

    typedef typename arg<tag::members, members<> >::type Members;
    typedef typename arg<tag::scope>::type Scope;

public:
};
} // end namespace event_detail

using event_detail::members;
using event_detail::scope;

template <
    typename Arg0, typename Arg1 = boost::parameter::void_,
    typename EnableADL = boost::proto::is_proto_expr
>
class event {
    typedef typename event_detail::signature::bind<Arg0, Arg1>::type Args;

public:
    BOOST_PROTO_EXTENDS(
        typename boost::proto::terminal<event_detail::event_impl<Args> >::type,
        event,
        boost::proto::default_domain
    )
};

} // end namespace sandbox
} // end namespace d2

#endif // !D2_SANDBOX_EVENT_HPP
<commit_msg>Fix the event generator in the sandbox.<commit_after>/**
 * This file defines the `event` class.
 */

#ifndef D2_SANDBOX_EVENT_HPP
#define D2_SANDBOX_EVENT_HPP

#include <d2/detail/pair_adjacent.hpp>
#include <d2/sandbox/parameter.hpp>

#include <boost/fusion/include/as_map.hpp>
#include <boost/fusion/include/at_key.hpp>
#include <boost/fusion/include/equal_to.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/mpl/remove.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/operators.hpp>
#include <boost/phoenix/core/argument.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
#include <boost/proto/proto.hpp>
#include <boost/serialization/access.hpp>

namespace d2 {
namespace sandbox {

namespace event_detail {
D2_PARAMETER_TEMPLATE_KEYWORD(scope)
namespace tag { struct members; }

struct unused;

template <typename Members>
struct sanitize_members
    : detail::pair_adjacent<
        typename boost::mpl::remove<Members, unused>::type
    >
{ };

#define D2_MAX_EVENT_MEMBERS 10
template <BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(
                                    D2_MAX_EVENT_MEMBERS, typename A, unused)>
struct members
    : parameter_template_keyword<
        tag::members,
        typename sanitize_members<
            boost::mpl::vector<BOOST_PP_ENUM_PARAMS(D2_MAX_EVENT_MEMBERS, A)>
        >::type
    >
{ };

template <typename Members_, typename Scope>
class auto_event : boost::equality_comparable<auto_event<Members_, Scope> > {
    typedef typename boost::fusion::result_of::as_map<Members_>::type Members;
    Members members_;

    friend class boost::serialization::access;
    template <typename Archive>
    void serialize(Archive& ar, unsigned int const /*version*/) {
        boost::fusion::for_each(members_, ar & boost::phoenix::arg_names::_1);
    }

public:
    typedef Scope event_scope;

    friend bool operator==(auto_event const& self, auto_event const& other) {
        return self.members_ == other.members_;
    }

    template <typename Key>
    friend typename boost::fusion::result_of::at_key<Members, Key>::type
    get(Key const&, auto_event& self) {
        return boost::fusion::at_key<Key>(self.members_);
    }

    template <typename Key>
    friend typename boost::fusion::result_of::at_key<Members const, Key>::type
    get(Key const&, auto_event const& self) {
        return boost::fusion::at_key<Key>(self.members_);
    }
};

typedef boost::parameter::parameters<
            boost::parameter::required<tag::scope>,
            boost::parameter::optional<tag::members>
        > make_auto_event_signature;

template <typename Args>
class make_auto_event {
    template <typename Tag, typename Default = boost::parameter::void_>
    struct arg
        : parameter_value_type<Args, Tag, Default>
    { };

    typedef typename members<>::value_type NoMembers;
    typedef typename arg<tag::members, NoMembers>::type Members;

    typedef typename arg<tag::scope>::type Scope;

public:
    typedef auto_event<Members, Scope> type;
};
} // end namespace event_detail

using event_detail::scope;
using event_detail::members;

template <typename A0, typename A1 = boost::parameter::void_>
struct event
    : event_detail::make_auto_event<
        typename event_detail::make_auto_event_signature::bind<A0, A1>::type
    >::type
{ };

} // end namespace sandbox
} // end namespace d2

#endif // !D2_SANDBOX_EVENT_HPP
<|endoftext|>