<commit_before>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/morphablemodel/io/cvssp.hpp
 *
 * Copyright 2014, 2015 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#ifndef EOS_IO_CVSSP_HPP
#define EOS_IO_CVSSP_HPP

#include "eos/morphablemodel/MorphableModel.hpp"

#include "Eigen/Core"

#include <array>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>

namespace eos {
namespace morphablemodel {

// Forward declaration
std::vector<std::array<double, 2>> load_isomap(std::string isomap_file);

/**
 * Load a shape or color model from a .scm file containing
 * a Morphable Model in the Surrey format. CVSSP's software
 * internally trains and stores the model in this custom binary
 * format and this class provides means to load them.
 *
 * Note on multi-resolution models: The landmarks to vertex-id mapping is
 * always the same. The lowest resolution model has all the landmarks defined
 * and for the higher resolutions, the mesh is divided from that on.
 * Note: For new landmarks we add, this might not be the case if we add them
 * in the highest resolution model, so take care!
 *
 * The PCA basis matrix stored in the file and loaded is the orthogonal PCA basis, i.e. it is not normalised
 * by the eigenvalues.
 *
 * @param[in] model_filename A binary .scm-file containing the model.
 * @param[in] isomap_file An optional path to an isomap containing texture coordinates.
 * @return The Morphable Model loaded from the file.
 * @throws ...
 */
inline MorphableModel load_scm_model(std::string model_filename, std::string isomap_file = std::string())
{
    using Eigen::MatrixXf;
    using Eigen::VectorXf;

    if (sizeof(unsigned int) != 4) // note/todo: maybe use uint32 or similar instead? Yep, but still we could encounter endianness-trouble.
    {
        std::cout << "Warning: We're reading 4 Bytes from the file but sizeof(unsigned int) != 4. Check the code/behaviour." << std::endl;
    }
    if (sizeof(double) != 8)
    {
        std::cout << "Warning: We're reading 8 Bytes from the file but sizeof(double) != 8. Check the code/behaviour." << std::endl;
    }

    std::ifstream model_file(model_filename, std::ios::binary);
    if (!model_file)
    {
        const std::string msg("Unable to open model file: " + model_filename);
        std::cout << msg << std::endl;
        throw std::runtime_error(msg);
    }

    // Reading the shape model
    // Read (reference?) num triangles and vertices
    unsigned int num_vertices = 0;
    unsigned int num_triangles = 0;
    model_file.read(reinterpret_cast<char*>(&num_vertices),
                    4); // 1 char = 1 byte. uint32=4bytes. float64=8bytes.
    model_file.read(reinterpret_cast<char*>(&num_triangles), 4);

    // Read triangles
    std::vector<std::array<int, 3>> triangle_list;

    triangle_list.resize(num_triangles);
    unsigned int v0, v1, v2;
    for (unsigned int i = 0; i < num_triangles; ++i)
    {
        v0 = v1 = v2 = 0;
        model_file.read(reinterpret_cast<char*>(&v0), 4); // would be nice to pass a &vector and do it in one
        model_file.read(reinterpret_cast<char*>(&v1), 4); // go, but didn't work. Maybe a cv::Mat would work?
        model_file.read(reinterpret_cast<char*>(&v2), 4);
        triangle_list[i][0] = v0;
        triangle_list[i][1] = v1;
        triangle_list[i][2] = v2;
    }

    // Read number of rows and columns of the shape projection matrix (pcaBasis)
    unsigned int num_shape_pca_coeffs = 0;
    unsigned int num_shape_dims = 0; // dimension of the shape vector (3*num_vertices)
    model_file.read(reinterpret_cast<char*>(&num_shape_pca_coeffs), 4);
    model_file.read(reinterpret_cast<char*>(&num_shape_dims), 4);

    if (3 * num_vertices != num_shape_dims)
    {
        std::cout << "Warning: Number of shape dimensions is not equal to three times the number of "
                     "vertices. Something will probably go wrong during the loading."
                  << std::endl;
    }

    // Read shape projection matrix
    MatrixXf orthonormal_pca_basis_shape(
        num_shape_dims, num_shape_pca_coeffs); // m x n (rows x cols) = num_shape_dims x num_shape_pca_coeffs
    std::cout << "Loading shape PCA basis matrix with " << orthonormal_pca_basis_shape.rows() << " rows and "
              << orthonormal_pca_basis_shape.cols() << " cols." << std::endl;
    for (unsigned int col = 0; col < num_shape_pca_coeffs; ++col)
    {
        for (unsigned int row = 0; row < num_shape_dims; ++row)
        {
            double var = 0.0;
            model_file.read(reinterpret_cast<char*>(&var), 8);
            orthonormal_pca_basis_shape(row, col) = static_cast<float>(var);
        }
    }

    // Read mean shape vector
    unsigned int mean_dims = 0; // dimension of the mean (3*num_vertices)
    model_file.read(reinterpret_cast<char*>(&mean_dims), 4);
    if (mean_dims != num_shape_dims)
    {
        std::cout << "Warning: Number of shape dimensions is not equal to the number of dimensions of the "
                     "mean. Something will probably go wrong during the loading."
                  << std::endl;
    }
    VectorXf mean_shape(mean_dims);
    unsigned int counter = 0;
    double vd0, vd1, vd2;
    for (unsigned int i = 0; i < mean_dims / 3; ++i)
    {
        vd0 = vd1 = vd2 = 0.0;
        model_file.read(reinterpret_cast<char*>(&vd0), 8);
        model_file.read(reinterpret_cast<char*>(&vd1), 8);
        model_file.read(reinterpret_cast<char*>(&vd2), 8);
        mean_shape(counter) = static_cast<float>(vd0);
        ++counter;
        mean_shape(counter) = static_cast<float>(vd1);
        ++counter;
        mean_shape(counter) = static_cast<float>(vd2);
        ++counter;
    }

    // Read shape eigenvalues
    unsigned int num_eigenvals_shape = 0;
    model_file.read(reinterpret_cast<char*>(&num_eigenvals_shape), 4);
    if (num_eigenvals_shape != num_shape_pca_coeffs)
    {
        std::cout << "Warning: Number of coefficients in the PCA basis matrix is not equal to the number of "
                     "eigenvalues. Something will probably go wrong during the loading."
                  << std::endl;
    }
    VectorXf eigenvalues_shape(num_eigenvals_shape);
    for (unsigned int i = 0; i < num_eigenvals_shape; ++i)
    {
        double var = 0.0;
        model_file.read(reinterpret_cast<char*>(&var), 8);
        eigenvalues_shape(i) = static_cast<float>(var);
    }

    const PcaModel shape_model(mean_shape, orthonormal_pca_basis_shape, eigenvalues_shape, triangle_list);

    // Reading the color model
    // Read number of rows and columns of projection matrix
    unsigned int num_color_pca_coeffs = 0;
    unsigned int num_color_dims = 0;
    model_file.read(reinterpret_cast<char*>(&num_color_pca_coeffs), 4);
    model_file.read(reinterpret_cast<char*>(&num_color_dims), 4);
    // Read color projection matrix
    MatrixXf orthonormal_pca_basis_color(num_color_dims, num_color_pca_coeffs);
    std::cout << "Loading color PCA basis matrix with " << orthonormal_pca_basis_color.rows() << " rows and "
              << orthonormal_pca_basis_color.cols() << " cols." << std::endl;
    for (unsigned int col = 0; col < num_color_pca_coeffs; ++col)
    {
        for (unsigned int row = 0; row < num_color_dims; ++row)
        {
            double var = 0.0;
            model_file.read(reinterpret_cast<char*>(&var), 8);
            orthonormal_pca_basis_color(row, col) = static_cast<float>(var);
        }
    }

    // Read mean color vector
    unsigned int color_mean_dims = 0; // dimension of the mean (3*num_vertices)
    model_file.read(reinterpret_cast<char*>(&color_mean_dims), 4);
    VectorXf mean_color(color_mean_dims);
    counter = 0;
    for (unsigned int i = 0; i < color_mean_dims / 3; ++i)
    {
        vd0 = vd1 = vd2 = 0.0;
        model_file.read(reinterpret_cast<char*>(&vd0),
                        8); // order in hdf5: RGB. Order in OCV: BGR. But order in vertex.color: RGB
        model_file.read(reinterpret_cast<char*>(&vd1), 8);
        model_file.read(reinterpret_cast<char*>(&vd2), 8);
        mean_color(counter) = static_cast<float>(vd0);
        ++counter;
        mean_color(counter) = static_cast<float>(vd1);
        ++counter;
        mean_color(counter) = static_cast<float>(vd2);
        ++counter;
    }

    // Read color eigenvalues
    unsigned int num_eigenvals_color = 0;
    model_file.read(reinterpret_cast<char*>(&num_eigenvals_color), 4);
    VectorXf eigenvalues_color(num_eigenvals_color);
    for (unsigned int i = 0; i < num_eigenvals_color; ++i)
    {
        double var = 0.0;
        model_file.read(reinterpret_cast<char*>(&var), 8);
        eigenvalues_color(i) = static_cast<float>(var);
    }

    const PcaModel color_model(mean_color, orthonormal_pca_basis_color, eigenvalues_color, triangle_list);

    model_file.close();

    // Load the isomap with texture coordinates if a filename has been given:
    std::vector<std::array<double, 2>> tex_coords;
    if (!isomap_file.empty())
    {
        tex_coords = load_isomap(isomap_file);
        if (shape_model.get_data_dimension() / 3.0f != tex_coords.size())
        {
            const std::string error_msg("Error, wrong number of texture coordinates. Don't have the same "
                                        "number of texcoords than the shape model has vertices.");
            std::cout << error_msg << std::endl;
            throw std::runtime_error(error_msg);
        }
    }

    return MorphableModel(shape_model, color_model, cpp17::nullopt, tex_coords);
};

/**
 * Load a set of 2D texture coordinates pre-generated by the isomap algorithm.
 * After loading, we rescale the coordinates to [0, 1] x [0, 1].
 *
 * @param[in] isomap_file Path to an isomap file containing texture coordinates.
 * @return The 2D texture coordinates for every vertex.
 * @throws ...
 */
inline std::vector<std::array<double, 2>> load_isomap(std::string isomap_file)
{
    using std::string;
    std::vector<float> x_coords, y_coords;
    string line;
    std::ifstream file(isomap_file);
    if (!file)
    {
        const string error_msg("The isomap file could not be opened. Did you specify a correct filename? " + isomap_file);
        throw std::runtime_error(error_msg);
    } else
    {
        while (getline(file, line))
        {
            std::istringstream iss(line);
            string x, y;
            iss >> x >> y;
            x_coords.push_back(std::stof(x));
            y_coords.push_back(std::stof(y));
        }
        file.close();
    }
    // Process the coordinates: Find the min/max and rescale to [0, 1] x [0, 1]
    const auto min_max_x = std::minmax_element(begin(x_coords), end(x_coords)); // min_max_x is a pair, first=min, second=max
    const auto min_max_y = std::minmax_element(begin(y_coords), end(y_coords));

    std::vector<std::array<double, 2>> tex_coords;
    const float divisor_x = *min_max_x.second - *min_max_x.first;
    const float divisor_y = *min_max_y.second - *min_max_y.first;
    for (int i = 0; i < x_coords.size(); ++i)
    {
        tex_coords.push_back(std::array<double, 2>{
            (x_coords[i] - *min_max_x.first) / divisor_x,
            1.0f - (y_coords[i] - *min_max_y.first) / divisor_y}); // We rescale to [0, 1] and at the same
                                                                   // time flip the y-coords (because in the
                                                                   // isomap, the coordinates are stored
                                                                   // upside-down).
    }

    return tex_coords;
};

} /* namespace morphablemodel */
} /* namespace eos */

#endif /* EOS_IO_CVSSP_HPP */
<commit_msg>Ran clang-format on io/cvssp.hpp<commit_after>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/morphablemodel/io/cvssp.hpp
 *
 * Copyright 2014, 2015 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#ifndef EOS_IO_CVSSP_HPP
#define EOS_IO_CVSSP_HPP

#include "eos/morphablemodel/MorphableModel.hpp"

#include "Eigen/Core"

#include <array>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>

namespace eos {
namespace morphablemodel {

// Forward declaration
std::vector<std::array<double, 2>> load_isomap(std::string isomap_file);

/**
 * Load a shape or color model from a .scm file containing
 * a Morphable Model in the Surrey format. CVSSP's software
 * internally trains and stores the model in this custom binary
 * format and this class provides means to load them.
 *
 * Note on multi-resolution models: The landmarks to vertex-id mapping is
 * always the same. The lowest resolution model has all the landmarks defined
 * and for the higher resolutions, the mesh is divided from that on.
 * Note: For new landmarks we add, this might not be the case if we add them
 * in the highest resolution model, so take care!
 *
 * The PCA basis matrix stored in the file and loaded is the orthogonal PCA basis, i.e. it is not normalised
 * by the eigenvalues.
 *
 * @param[in] model_filename A binary .scm-file containing the model.
 * @param[in] isomap_file An optional path to an isomap containing texture coordinates.
 * @return The Morphable Model loaded from the file.
 * @throws ...
 */
inline MorphableModel load_scm_model(std::string model_filename, std::string isomap_file = std::string())
{
    using Eigen::MatrixXf;
    using Eigen::VectorXf;

    if (sizeof(unsigned int) != 4) // Note: maybe use uint32 or similar instead? Yep, but still we could
                                   // encounter endianness-trouble.
    {
        std::cout << "Warning: We're reading 4 Bytes from the file but sizeof(unsigned int) != 4. Check the "
                     "code/behaviour."
                  << std::endl;
    }
    if (sizeof(double) != 8)
    {
        std::cout << "Warning: We're reading 8 Bytes from the file but sizeof(double) != 8. Check the "
                     "code/behaviour."
                  << std::endl;
    }

    std::ifstream model_file(model_filename, std::ios::binary);
    if (!model_file)
    {
        const std::string msg("Unable to open model file: " + model_filename);
        std::cout << msg << std::endl;
        throw std::runtime_error(msg);
    }

    // Reading the shape model
    // Read (reference?) num triangles and vertices
    unsigned int num_vertices = 0;
    unsigned int num_triangles = 0;
    model_file.read(reinterpret_cast<char*>(&num_vertices),
                    4); // 1 char = 1 byte. uint32=4bytes. float64=8bytes.
    model_file.read(reinterpret_cast<char*>(&num_triangles), 4);

    // Read triangles
    std::vector<std::array<int, 3>> triangle_list;

    triangle_list.resize(num_triangles);
    unsigned int v0, v1, v2;
    for (unsigned int i = 0; i < num_triangles; ++i)
    {
        v0 = v1 = v2 = 0;
        model_file.read(reinterpret_cast<char*>(&v0), 4); // would be nice to pass a &vector and do it in one
        model_file.read(reinterpret_cast<char*>(&v1), 4); // go, but didn't work.
        model_file.read(reinterpret_cast<char*>(&v2), 4);
        triangle_list[i][0] = v0;
        triangle_list[i][1] = v1;
        triangle_list[i][2] = v2;
    }

    // Read number of rows and columns of the shape projection matrix (pcaBasis)
    unsigned int num_shape_pca_coeffs = 0;
    unsigned int num_shape_dims = 0; // dimension of the shape vector (3*num_vertices)
    model_file.read(reinterpret_cast<char*>(&num_shape_pca_coeffs), 4);
    model_file.read(reinterpret_cast<char*>(&num_shape_dims), 4);

    if (3 * num_vertices != num_shape_dims)
    {
        std::cout << "Warning: Number of shape dimensions is not equal to three times the number of "
                     "vertices. Something will probably go wrong during the loading."
                  << std::endl;
    }

    // Read shape projection matrix
    MatrixXf orthonormal_pca_basis_shape(
        num_shape_dims, num_shape_pca_coeffs); // m x n (rows x cols) = num_shape_dims x num_shape_pca_coeffs
    std::cout << "Loading shape PCA basis matrix with " << orthonormal_pca_basis_shape.rows() << " rows and "
              << orthonormal_pca_basis_shape.cols() << " cols." << std::endl;
    for (unsigned int col = 0; col < num_shape_pca_coeffs; ++col)
    {
        for (unsigned int row = 0; row < num_shape_dims; ++row)
        {
            double var = 0.0;
            model_file.read(reinterpret_cast<char*>(&var), 8);
            orthonormal_pca_basis_shape(row, col) = static_cast<float>(var);
        }
    }

    // Read mean shape vector
    unsigned int mean_dims = 0; // dimension of the mean (3*num_vertices)
    model_file.read(reinterpret_cast<char*>(&mean_dims), 4);
    if (mean_dims != num_shape_dims)
    {
        std::cout << "Warning: Number of shape dimensions is not equal to the number of dimensions of the "
                     "mean. Something will probably go wrong during the loading."
                  << std::endl;
    }
    VectorXf mean_shape(mean_dims);
    unsigned int counter = 0;
    double vd0, vd1, vd2;
    for (unsigned int i = 0; i < mean_dims / 3; ++i)
    {
        vd0 = vd1 = vd2 = 0.0;
        model_file.read(reinterpret_cast<char*>(&vd0), 8);
        model_file.read(reinterpret_cast<char*>(&vd1), 8);
        model_file.read(reinterpret_cast<char*>(&vd2), 8);
        mean_shape(counter) = static_cast<float>(vd0);
        ++counter;
        mean_shape(counter) = static_cast<float>(vd1);
        ++counter;
        mean_shape(counter) = static_cast<float>(vd2);
        ++counter;
    }

    // Read shape eigenvalues
    unsigned int num_eigenvals_shape = 0;
    model_file.read(reinterpret_cast<char*>(&num_eigenvals_shape), 4);
    if (num_eigenvals_shape != num_shape_pca_coeffs)
    {
        std::cout << "Warning: Number of coefficients in the PCA basis matrix is not equal to the number of "
                     "eigenvalues. Something will probably go wrong during the loading."
                  << std::endl;
    }
    VectorXf eigenvalues_shape(num_eigenvals_shape);
    for (unsigned int i = 0; i < num_eigenvals_shape; ++i)
    {
        double var = 0.0;
        model_file.read(reinterpret_cast<char*>(&var), 8);
        eigenvalues_shape(i) = static_cast<float>(var);
    }

    const PcaModel shape_model(mean_shape, orthonormal_pca_basis_shape, eigenvalues_shape, triangle_list);

    // Reading the color model
    // Read number of rows and columns of projection matrix
    unsigned int num_color_pca_coeffs = 0;
    unsigned int num_color_dims = 0;
    model_file.read(reinterpret_cast<char*>(&num_color_pca_coeffs), 4);
    model_file.read(reinterpret_cast<char*>(&num_color_dims), 4);
    // Read color projection matrix
    MatrixXf orthonormal_pca_basis_color(num_color_dims, num_color_pca_coeffs);
    std::cout << "Loading color PCA basis matrix with " << orthonormal_pca_basis_color.rows() << " rows and "
              << orthonormal_pca_basis_color.cols() << " cols." << std::endl;
    for (unsigned int col = 0; col < num_color_pca_coeffs; ++col)
    {
        for (unsigned int row = 0; row < num_color_dims; ++row)
        {
            double var = 0.0;
            model_file.read(reinterpret_cast<char*>(&var), 8);
            orthonormal_pca_basis_color(row, col) = static_cast<float>(var);
        }
    }

    // Read mean color vector
    unsigned int color_mean_dims = 0; // dimension of the mean (3*num_vertices)
    model_file.read(reinterpret_cast<char*>(&color_mean_dims), 4);
    VectorXf mean_color(color_mean_dims);
    counter = 0;
    for (unsigned int i = 0; i < color_mean_dims / 3; ++i)
    {
        vd0 = vd1 = vd2 = 0.0;
        model_file.read(reinterpret_cast<char*>(&vd0),
                        8); // order in hdf5: RGB. Order in OCV: BGR. But order in vertex.color: RGB
        model_file.read(reinterpret_cast<char*>(&vd1), 8);
        model_file.read(reinterpret_cast<char*>(&vd2), 8);
        mean_color(counter) = static_cast<float>(vd0);
        ++counter;
        mean_color(counter) = static_cast<float>(vd1);
        ++counter;
        mean_color(counter) = static_cast<float>(vd2);
        ++counter;
    }

    // Read color eigenvalues
    unsigned int num_eigenvals_color = 0;
    model_file.read(reinterpret_cast<char*>(&num_eigenvals_color), 4);
    VectorXf eigenvalues_color(num_eigenvals_color);
    for (unsigned int i = 0; i < num_eigenvals_color; ++i)
    {
        double var = 0.0;
        model_file.read(reinterpret_cast<char*>(&var), 8);
        eigenvalues_color(i) = static_cast<float>(var);
    }

    const PcaModel color_model(mean_color, orthonormal_pca_basis_color, eigenvalues_color, triangle_list);

    model_file.close();

    // Load the isomap with texture coordinates if a filename has been given:
    std::vector<std::array<double, 2>> tex_coords;
    if (!isomap_file.empty())
    {
        tex_coords = load_isomap(isomap_file);
        if (shape_model.get_data_dimension() / 3.0f != tex_coords.size())
        {
            const std::string error_msg("Error, wrong number of texture coordinates. Don't have the same "
                                        "number of texcoords than the shape model has vertices.");
            std::cout << error_msg << std::endl;
            throw std::runtime_error(error_msg);
        }
    }

    return MorphableModel(shape_model, color_model, cpp17::nullopt, tex_coords);
};

/**
 * Load a set of 2D texture coordinates pre-generated by the isomap algorithm.
 * After loading, we rescale the coordinates to [0, 1] x [0, 1].
 *
 * @param[in] isomap_file Path to an isomap file containing texture coordinates.
 * @return The 2D texture coordinates for every vertex.
 * @throws ...
 */
inline std::vector<std::array<double, 2>> load_isomap(std::string isomap_file)
{
    using std::string;
    std::vector<float> x_coords, y_coords;
    string line;
    std::ifstream file(isomap_file);
    if (!file)
    {
        const string error_msg("The isomap file could not be opened. Did you specify a correct filename? " +
                               isomap_file);
        throw std::runtime_error(error_msg);
    } else
    {
        while (getline(file, line))
        {
            std::istringstream iss(line);
            string x, y;
            iss >> x >> y;
            x_coords.push_back(std::stof(x));
            y_coords.push_back(std::stof(y));
        }
        file.close();
    }
    // Process the coordinates: Find the min/max and rescale to [0, 1] x [0, 1]
    const auto min_max_x =
        std::minmax_element(begin(x_coords), end(x_coords)); // min_max_x is a pair, first=min, second=max
    const auto min_max_y = std::minmax_element(begin(y_coords), end(y_coords));

    std::vector<std::array<double, 2>> tex_coords;
    const float divisor_x = *min_max_x.second - *min_max_x.first;
    const float divisor_y = *min_max_y.second - *min_max_y.first;
    for (int i = 0; i < x_coords.size(); ++i)
    {
        tex_coords.push_back(std::array<double, 2>{
            (x_coords[i] - *min_max_x.first) / divisor_x,
            1.0f - (y_coords[i] - *min_max_y.first) /
                       divisor_y}); // We rescale to [0, 1] and at the same time flip the y-coords (because in
                                    // the isomap, the coordinates are stored upside-down).
    }

    return tex_coords;
};

} /* namespace morphablemodel */
} /* namespace eos */

#endif /* EOS_IO_CVSSP_HPP */
<|endoftext|>


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

using namespace std;

// Define a Node/ Block in the Board
class Node
{
    public:
        bool visited;
        bool mine;
        int num;
};

// Define the Board
// Place mines Randomly
// Get count of surrounding mines of all the non- mine blocks and place it

vector<vector<Node> > Create_Board(int m,int n)
{
    vector<vector<Node> > Board(m);
    for(int i = 0; i < m; i++)
    {
	vector<Node> tmp(n);
	for(int j=0; j<n; j++)
	{
            tmp[j].visited = false;
            tmp[j].mine = false;
            tmp[j].num = 0;
        }
        Board[i] = tmp;
        tmp.clear();
    }
    return Board;
}

void place_mines(vector<vector<Node> >&Board, int &N)
{
    if (N == 0) return;
    if(Board.size() == 0)
        return;

    int m = Board.size(); int n = Board[0].size();
    if(N >= m*n)
    {
	for(int i = 0; i < m; i++)
        {
	    for(int j = 0; j < n; j++)
	        Board[i][j].mine = true;
        }
	return;
    }

    int random = rand() % (m * n);
    int row = random / n; int col = random / m;

    if(Board[row][col].mine == false)
    {
       Board[row][col].mine = true;
       N--;
    }
    return place_mines(Board,N);
}

int check(vector<vector<Node> >&Board,int i, int j)
{
    if(i >= 0 && i<Board.size() && j >= 0 && j < Board[0].size())
    {
        if(Board[i][j].mine == true)
	    return 1;
    }
    return 0;
}

int get_num(vector<vector<Node> >&Board,int i, int j)
{
    int num = 0;
    for(int p=i-1; p<i+1;p++)
    {
        for(int q = j-1; q < j+1; q++)
            num += check(Board,p,q);
    }
    return num;
}
void set_number(vector<vector<Node> >&Board)
{
    if(Board.size() == 0)
        return;
    for(int i = 0; i< Board.size(); i++)
    {
        for(int j=0; j < Board[i].size(); j++)
        {
            if(Board[i][j].mine == false)
                Board[i][j].num = get_num(Board,i,j);
        }
    }

}

int main()
{

    return 0;
}

<commit_msg>Updating Minesweeper<commit_after>#include <iostream>
#include <vector>

using namespace std;

// Define a Node/ Block in the Board
class Node
{
    public:
        bool visited;
        bool mine;
        int num;
};

// Define the Board
// Place mines Randomly
// Get count of surrounding mines of all the non- mine blocks and place it

vector<vector<Node> > Create_Board(int m,int n)
{
    vector<vector<Node> > Board(m);
    for(int i = 0; i < m; i++)
    {
	vector<Node> tmp(n);
	for(int j=0; j<n; j++)
	{
            tmp[j].visited = false;
            tmp[j].mine = false;
            tmp[j].num = 0;
        }
        Board[i] = tmp;
        tmp.clear();
    }
    return Board;
}

void place_mines(vector<vector<Node> >&Board, int &N)
{
    if (N == 0) return;
    if(Board.size() == 0)
        return;

    int m = Board.size(); int n = Board[0].size();
    if(N >= m*n)
    {
	for(int i = 0; i < m; i++)
        {
	    for(int j = 0; j < n; j++)
	        Board[i][j].mine = true;
        }
	return;
    }

    int random = rand() % (m * n);
    int row = random / n; int col = random % m;

    if(Board[row][col].mine == false)
    {
       Board[row][col].mine = true;
       N--;
    }
    return place_mines(Board,N);
}

int check(vector<vector<Node> >&Board,int i, int j)
{
    if(i >= 0 && i<Board.size() && j >= 0 && j < Board[0].size())
    {
        if(Board[i][j].mine == true)
	    return 1;
    }
    return 0;
}

int get_num(vector<vector<Node> >&Board,int i, int j)
{
    int num = 0;
    for(int p=i-1; p<i+1;p++)
    {
        for(int q = j-1; q < j+1; q++)
            num += check(Board,p,q);
    }
    return num;
}
void set_number(vector<vector<Node> >&Board)
{
    if(Board.size() == 0)
        return;
    for(int i = 0; i< Board.size(); i++)
    {
        for(int j=0; j < Board[i].size(); j++)
        {
            if(Board[i][j].mine == false)
                Board[i][j].num = get_num(Board,i,j);
        }
    }

}

int main()
{

    return 0;
}

<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2012 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
same license as the rest of the engine.
-----------------------------------------------------------------------------
*/
/*
-----------------------------------------------------------------------------
Filename:    ParticleGS.cpp
Description: Demonstrates the use of the geometry shader and render to vertex
	buffer to create a particle system that is entirely calculated on the GPU.
	Partial implementation of ParticlesGS example from Microsoft's DirectX 10
	SDK : http://msdn.microsoft.com/en-us/library/ee416421.aspx
-----------------------------------------------------------------------------
*/

#include "ProceduralManualObject.h"
#include "OgreRenderToVertexBuffer.h"
#include "RandomTools.h"
#include "SamplePlugin.h"
#include "SdkSample.h"

using namespace Ogre;
using namespace OgreBites;

//#define LOG_GENERATED_BUFFER
const Vector3 GRAVITY_VECTOR = Vector3(0, -9.8, 0);

#ifdef LOG_GENERATED_BUFFER
struct FireworkParticle
{
	float pos[3];
	float timer;
	float type;
	float vel[3];
};
#endif

class _OgreSampleClassExport Sample_ParticleGS : public SdkSample
{
public:
    Sample_ParticleGS()
	{
		mInfo["Title"] = "Geometry Shader Particle System";
		mInfo["Description"] = "A demo of particle systems using geometry shaders and render to vertex buffers.";
		mInfo["Thumbnail"] = "thumb_particlegs.png";
		mInfo["Category"] = "Effects";
    }

protected:

	void createProceduralParticleSystem()
	{
		mParticleSystem = static_cast<ProceduralManualObject*>
			(mSceneMgr->createMovableObject("ParticleGSEntity", ProceduralManualObjectFactory::FACTORY_TYPE_NAME));
		mParticleSystem->setMaterial("Ogre/ParticleGS/Display");

		//Generate the geometry that will seed the particle system
		ManualObject* particleSystemSeed = mSceneMgr->createManualObject("ParticleSeed");
		//This needs to be the initial launcher particle
		particleSystemSeed->begin("Ogre/ParticleGS/Display", RenderOperation::OT_POINT_LIST);
		particleSystemSeed->position(0,0,0); //Position
		particleSystemSeed->textureCoord(1); //Timer
		particleSystemSeed->textureCoord(0); //Type
		particleSystemSeed->textureCoord(0,0,0); //Velocity
		particleSystemSeed->end();

		//Generate the RenderToBufferObject
		RenderToVertexBufferSharedPtr r2vbObject =
			HardwareBufferManager::getSingleton().createRenderToVertexBuffer();
		r2vbObject->setRenderToBufferMaterialName("Ogre/ParticleGS/Generate");

		//Apply the random texture
		TexturePtr randomTexture = RandomTools::generateRandomVelocityTexture();
		r2vbObject->getRenderToBufferMaterial()->getBestTechnique()->getPass(0)->
			getTextureUnitState("RandomTexture")->setTextureName(
			randomTexture->getName(), randomTexture->getTextureType());

		r2vbObject->setOperationType(RenderOperation::OT_POINT_LIST);
		r2vbObject->setMaxVertexCount(16000);
		r2vbObject->setResetsEveryUpdate(false);
		VertexDeclaration* vertexDecl = r2vbObject->getVertexDeclaration();
		size_t offset = 0;
		offset += vertexDecl->addElement(0, offset, VET_FLOAT3, VES_POSITION).getSize(); //Position
		offset += vertexDecl->addElement(0, offset, VET_FLOAT1, VES_TEXTURE_COORDINATES, 0).getSize(); //Timer
		offset += vertexDecl->addElement(0, offset, VET_FLOAT1, VES_TEXTURE_COORDINATES, 1).getSize(); //Type
		vertexDecl->addElement(0, offset, VET_FLOAT3, VES_TEXTURE_COORDINATES, 2).getSize(); //Velocity

		//Bind the two together
		mParticleSystem->setRenderToVertexBuffer(r2vbObject);
		mParticleSystem->setManualObject(particleSystemSeed);

		//Set bounds
		AxisAlignedBox aabb;
		aabb.setMinimum(-100,-100,-100);
		aabb.setMaximum(100,100,100);
		mParticleSystem->setBoundingBox(aabb);
	}

    void testCapabilities(const RenderSystemCapabilities* caps)
    {
        if (!caps->hasCapability(RSC_GEOMETRY_PROGRAM))
        {
			OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your render system / hardware does not support geometry programs, "
                        "so you cannot run this sample. Sorry!",
                        "Sample_ParticleGS::createScene");
        }
		if (!caps->hasCapability(RSC_HWRENDER_TO_VERTEX_BUFFER))
        {
			OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your render system / hardware does not support render to vertex buffers, "
                        "so you cannot run this sample. Sorry!",
                        "Sample_ParticleGS::createScene");
        }
    }

	void setupContent(void)
    {
        demoTime = 0;

        mProceduralManualObjectFactory = new ProceduralManualObjectFactory;
		createProceduralParticleSystem();

		mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(mParticleSystem);
		//mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(mParticleSystem->getManualObject());
		mCamera->setPosition(0,35,-100);
		mCamera->lookAt(0,35,0);

		//Add an ogre head to the scene
		SceneNode* ogreHeadSN = mSceneMgr->getRootSceneNode()->createChildSceneNode();
		Entity *ogreHead = mSceneMgr->createEntity("head", "ogrehead.mesh");
		ogreHeadSN->scale(0.1,0.1,0.1);
		ogreHeadSN->yaw(Degree(180));
		ogreHeadSN->attachObject(ogreHead);

		//Add a plane to the scene
		Plane plane;
		plane.normal = Vector3::UNIT_Y;
		plane.d = 100;
		MeshManager::getSingleton().createPlane("Myplane",
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
			1500,1500,20,20,true,1,60,60,Vector3::UNIT_Z);
		Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
		pPlaneEnt->setMaterialName("Examples/Rockwall");
		pPlaneEnt->setCastShadows(false);
		mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,95,0))->attachObject(pPlaneEnt);
    }

    void cleanupContent()
    {
        Root::getSingleton().removeMovableObjectFactory(mProceduralManualObjectFactory);
        MeshManager::getSingleton().remove("Myplane");
    }

	bool frameStarted(const FrameEvent& evt)
	{
		//Set shader parameters
		GpuProgramParametersSharedPtr geomParams = mParticleSystem->
			getRenderToVertexBuffer()->getRenderToBufferMaterial()->
			getBestTechnique()->getPass(0)->getGeometryProgramParameters();
        if (geomParams->_findNamedConstantDefinition("elapsedTime"))
        {
            geomParams->setNamedConstant("elapsedTime", evt.timeSinceLastFrame);
		}
        demoTime += evt.timeSinceLastFrame;
		if (geomParams->_findNamedConstantDefinition("globalTime"))
		{
			geomParams->setNamedConstant("globalTime", demoTime);
		}
		if (geomParams->_findNamedConstantDefinition("frameGravity"))
		{
			geomParams->setNamedConstant("frameGravity", GRAVITY_VECTOR * evt.timeSinceLastFrame);
		}
		return SdkSample::frameStarted(evt);
	}

#ifdef LOG_GENERATED_BUFFER
	bool frameEnded(const FrameEvent& evt)
	{
		//This will only work if the vertex buffer usage is dynamic (see R2VB implementation)
		LogManager::getSingleton().getDefaultLog()->stream() <<
			"Particle system for frame " <<	Root::getSingleton().getNextFrameNumber();
		RenderOperation renderOp;
		mParticleSystem->getRenderToVertexBuffer()->getRenderOperation(renderOp);
		const HardwareVertexBufferSharedPtr& vertexBuffer =
			renderOp.vertexData->vertexBufferBinding->getBuffer(0);

		assert(vertexBuffer->getVertexSize() == sizeof(FireworkParticle));
		FireworkParticle* particles = static_cast<FireworkParticle*>
			(vertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));

		for (size_t i=0; i<renderOp.vertexData->vertexCount; i++)
		{
			FireworkParticle& p = particles[i];
			LogManager::getSingleton().getDefaultLog()->stream() <<
				"FireworkParticle " << i+1 << " : " <<
				"Position : " << p.pos[0] << " " << p.pos[1] << " " << p.pos[2] << " , " <<
				"Timer : " << p.timer << " , " <<
				"Type : " << p.type << " , " <<
				"Velocity : " << p.vel[0] << " " << p.vel[1] << " " << p.vel[2];
		}

		vertexBuffer->unlock();
		return SdkSample::frameEnded(evt);
	}
#endif

    Real demoTime;
    ProceduralManualObject* mParticleSystem;
    ProceduralManualObjectFactory *mProceduralManualObjectFactory;
};

#ifndef OGRE_STATIC_LIB

SamplePlugin* sp;
Sample* s;

extern "C" _OgreSampleExport void dllStartPlugin()
{
	s = new Sample_ParticleGS;
	sp = OGRE_NEW SamplePlugin(s->getInfo()["Title"] + " Sample");
	sp->addSample(s);
	Root::getSingleton().installPlugin(sp);
}

extern "C" _OgreSampleExport void dllStopPlugin()
{
	Root::getSingleton().uninstallPlugin(sp);
	OGRE_DELETE sp;
	delete s;
}
#endif

<commit_msg>Create and destroy the ProceduralManualObjectFactory in the ParticleGS sample. Fixes errors on startup<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2012 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
same license as the rest of the engine.
-----------------------------------------------------------------------------
*/
/*
-----------------------------------------------------------------------------
Filename:    ParticleGS.cpp
Description: Demonstrates the use of the geometry shader and render to vertex
	buffer to create a particle system that is entirely calculated on the GPU.
	Partial implementation of ParticlesGS example from Microsoft's DirectX 10
	SDK : http://msdn.microsoft.com/en-us/library/ee416421.aspx
-----------------------------------------------------------------------------
*/

#include "ProceduralManualObject.h"
#include "OgreRenderToVertexBuffer.h"
#include "RandomTools.h"
#include "SamplePlugin.h"
#include "SdkSample.h"

using namespace Ogre;
using namespace OgreBites;

//#define LOG_GENERATED_BUFFER
const Vector3 GRAVITY_VECTOR = Vector3(0, -9.8, 0);

#ifdef LOG_GENERATED_BUFFER
struct FireworkParticle
{
	float pos[3];
	float timer;
	float type;
	float vel[3];
};
#endif

class _OgreSampleClassExport Sample_ParticleGS : public SdkSample
{
public:
    Sample_ParticleGS()
	{
		mInfo["Title"] = "Geometry Shader Particle System";
		mInfo["Description"] = "A demo of particle systems using geometry shaders and render to vertex buffers.";
		mInfo["Thumbnail"] = "thumb_particlegs.png";
		mInfo["Category"] = "Effects";
    }

protected:

	void createProceduralParticleSystem()
	{
		mParticleSystem = static_cast<ProceduralManualObject*>
			(mSceneMgr->createMovableObject("ParticleGSEntity", ProceduralManualObjectFactory::FACTORY_TYPE_NAME));
		mParticleSystem->setMaterial("Ogre/ParticleGS/Display");

		//Generate the geometry that will seed the particle system
		ManualObject* particleSystemSeed = mSceneMgr->createManualObject("ParticleSeed");
		//This needs to be the initial launcher particle
		particleSystemSeed->begin("Ogre/ParticleGS/Display", RenderOperation::OT_POINT_LIST);
		particleSystemSeed->position(0,0,0); //Position
		particleSystemSeed->textureCoord(1); //Timer
		particleSystemSeed->textureCoord(0); //Type
		particleSystemSeed->textureCoord(0,0,0); //Velocity
		particleSystemSeed->end();

		//Generate the RenderToBufferObject
		RenderToVertexBufferSharedPtr r2vbObject =
			HardwareBufferManager::getSingleton().createRenderToVertexBuffer();
		r2vbObject->setRenderToBufferMaterialName("Ogre/ParticleGS/Generate");

		//Apply the random texture
		TexturePtr randomTexture = RandomTools::generateRandomVelocityTexture();
		r2vbObject->getRenderToBufferMaterial()->getBestTechnique()->getPass(0)->
			getTextureUnitState("RandomTexture")->setTextureName(
			randomTexture->getName(), randomTexture->getTextureType());

		r2vbObject->setOperationType(RenderOperation::OT_POINT_LIST);
		r2vbObject->setMaxVertexCount(16000);
		r2vbObject->setResetsEveryUpdate(false);
		VertexDeclaration* vertexDecl = r2vbObject->getVertexDeclaration();
		size_t offset = 0;
		offset += vertexDecl->addElement(0, offset, VET_FLOAT3, VES_POSITION).getSize(); //Position
		offset += vertexDecl->addElement(0, offset, VET_FLOAT1, VES_TEXTURE_COORDINATES, 0).getSize(); //Timer
		offset += vertexDecl->addElement(0, offset, VET_FLOAT1, VES_TEXTURE_COORDINATES, 1).getSize(); //Type
		vertexDecl->addElement(0, offset, VET_FLOAT3, VES_TEXTURE_COORDINATES, 2).getSize(); //Velocity

		//Bind the two together
		mParticleSystem->setRenderToVertexBuffer(r2vbObject);
		mParticleSystem->setManualObject(particleSystemSeed);

		//Set bounds
		AxisAlignedBox aabb;
		aabb.setMinimum(-100,-100,-100);
		aabb.setMaximum(100,100,100);
		mParticleSystem->setBoundingBox(aabb);
	}

    void testCapabilities(const RenderSystemCapabilities* caps)
    {
        if (!caps->hasCapability(RSC_GEOMETRY_PROGRAM))
        {
			OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your render system / hardware does not support geometry programs, "
                        "so you cannot run this sample. Sorry!",
                        "Sample_ParticleGS::createScene");
        }
		if (!caps->hasCapability(RSC_HWRENDER_TO_VERTEX_BUFFER))
        {
			OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your render system / hardware does not support render to vertex buffers, "
                        "so you cannot run this sample. Sorry!",
                        "Sample_ParticleGS::createScene");
        }
    }

	void setupContent(void)
    {
        demoTime = 0;

        mProceduralManualObjectFactory = OGRE_NEW ProceduralManualObjectFactory();
        Root::getSingleton().addMovableObjectFactory(mProceduralManualObjectFactory);

		createProceduralParticleSystem();

		mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(mParticleSystem);
		//mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(mParticleSystem->getManualObject());
		mCamera->setPosition(0,35,-100);
		mCamera->lookAt(0,35,0);

		//Add an ogre head to the scene
		SceneNode* ogreHeadSN = mSceneMgr->getRootSceneNode()->createChildSceneNode();
		Entity *ogreHead = mSceneMgr->createEntity("head", "ogrehead.mesh");
		ogreHeadSN->scale(0.1,0.1,0.1);
		ogreHeadSN->yaw(Degree(180));
		ogreHeadSN->attachObject(ogreHead);

		//Add a plane to the scene
		Plane plane;
		plane.normal = Vector3::UNIT_Y;
		plane.d = 100;
		MeshManager::getSingleton().createPlane("Myplane",
			ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
			1500,1500,20,20,true,1,60,60,Vector3::UNIT_Z);
		Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" );
		pPlaneEnt->setMaterialName("Examples/Rockwall");
		pPlaneEnt->setCastShadows(false);
		mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,95,0))->attachObject(pPlaneEnt);
    }

    void cleanupContent()
    {
        Root::getSingleton().removeMovableObjectFactory(mProceduralManualObjectFactory);
        OGRE_DELETE mProceduralManualObjectFactory;
        mProceduralManualObjectFactory = 0;

        MeshManager::getSingleton().remove("Myplane");
    }

	bool frameStarted(const FrameEvent& evt)
	{
		//Set shader parameters
		GpuProgramParametersSharedPtr geomParams = mParticleSystem->
			getRenderToVertexBuffer()->getRenderToBufferMaterial()->
			getBestTechnique()->getPass(0)->getGeometryProgramParameters();
        if (geomParams->_findNamedConstantDefinition("elapsedTime"))
        {
            geomParams->setNamedConstant("elapsedTime", evt.timeSinceLastFrame);
		}
        demoTime += evt.timeSinceLastFrame;
		if (geomParams->_findNamedConstantDefinition("globalTime"))
		{
			geomParams->setNamedConstant("globalTime", demoTime);
		}
		if (geomParams->_findNamedConstantDefinition("frameGravity"))
		{
			geomParams->setNamedConstant("frameGravity", GRAVITY_VECTOR * evt.timeSinceLastFrame);
		}
		return SdkSample::frameStarted(evt);
	}

#ifdef LOG_GENERATED_BUFFER
	bool frameEnded(const FrameEvent& evt)
	{
		//This will only work if the vertex buffer usage is dynamic (see R2VB implementation)
		LogManager::getSingleton().getDefaultLog()->stream() <<
			"Particle system for frame " <<	Root::getSingleton().getNextFrameNumber();
		RenderOperation renderOp;
		mParticleSystem->getRenderToVertexBuffer()->getRenderOperation(renderOp);
		const HardwareVertexBufferSharedPtr& vertexBuffer =
			renderOp.vertexData->vertexBufferBinding->getBuffer(0);

		assert(vertexBuffer->getVertexSize() == sizeof(FireworkParticle));
		FireworkParticle* particles = static_cast<FireworkParticle*>
			(vertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));

		for (size_t i=0; i<renderOp.vertexData->vertexCount; i++)
		{
			FireworkParticle& p = particles[i];
			LogManager::getSingleton().getDefaultLog()->stream() <<
				"FireworkParticle " << i+1 << " : " <<
				"Position : " << p.pos[0] << " " << p.pos[1] << " " << p.pos[2] << " , " <<
				"Timer : " << p.timer << " , " <<
				"Type : " << p.type << " , " <<
				"Velocity : " << p.vel[0] << " " << p.vel[1] << " " << p.vel[2];
		}

		vertexBuffer->unlock();
		return SdkSample::frameEnded(evt);
	}
#endif

    Real demoTime;
    ProceduralManualObject* mParticleSystem;
    ProceduralManualObjectFactory *mProceduralManualObjectFactory;
};

#ifndef OGRE_STATIC_LIB

SamplePlugin* sp;
Sample* s;

extern "C" _OgreSampleExport void dllStartPlugin()
{
	s = new Sample_ParticleGS;
	sp = OGRE_NEW SamplePlugin(s->getInfo()["Title"] + " Sample");
	sp->addSample(s);
	Root::getSingleton().installPlugin(sp);
}

extern "C" _OgreSampleExport void dllStopPlugin()
{
	Root::getSingleton().uninstallPlugin(sp);
	OGRE_DELETE sp;
	delete s;
}
#endif

<|endoftext|>


<commit_before>#ifndef NTW_FUNCWRAPPER
#define NTW_FUNCWRAPPER

#include <Socket/SocketSerialized.hpp>
#include <Socket/define.hpp>

namespace ntw
{
    extern void dispatch(int id,SocketSerialized& request);

    class FuncWrapper
    {
        public:
            FuncWrapper() = delete;
            FuncWrapper(const FuncWrapper&) = delete;
            FuncWrapper& operator=(const FuncWrapper&) = delete;

            static int msg(SocketSerialized& sock,const std::string message,unsigned int code); ///< initialise the socket (client : verify the msg, serveur: send hello)
            static int verifyIsConnected(SocketSerialized& sock);

            class srv
            {
                public:
                    enum FUNCTONS_ID{UNKNOW=-1};
                    static void dispatch(SocketSerialized& request);

                    template<typename Ret,typename ... Args>
                    static Ret exec(Ret(*func)(SocketSerialized&,Args ...),SocketSerialized& sock);

                private:
                    srv() = delete;
                    srv& operator=(const srv&)=delete;
            };

            class cli
            {
                public:
                    template<typename ... Args>
                    static void addPackage(int id,SocketSerialized& sock,Args& ... args);

                    template<typename T,typename ... Args>
                    static void addPackage(SocketSerialized& sock,T& a,Args& ... args);

                    static void addPackage(SocketSerialized& sock);

                    template<typename Ret,typename ... Args>
                    static Ret send(SocketSerialized& sock,int id,Args&& ... args);

                private:
                    cli() = delete;
                    cli& operator=(const cli&) = delete;
            };
    };
};

#include <Socket/FuncWrapper.tpl>

#endif
<commit_msg>add doc<commit_after>#ifndef NTW_FUNCWRAPPER
#define NTW_FUNCWRAPPER

#include <Socket/SocketSerialized.hpp>
#include <Socket/define.hpp>

namespace ntw
{
    /**
     * \brief the external function to call whene recv a message
     * \param id the function id
     * \param request the request who send the request
     */
    extern void dispatch(int id,SocketSerialized& request);

    class FuncWrapper
    {
        public:
            FuncWrapper() = delete;
            FuncWrapper(const FuncWrapper&) = delete;
            FuncWrapper& operator=(const FuncWrapper&) = delete;

            /**
             * \brief send a message to the sock. Use to send errors
             * \param sock to use
             * \param message to send
             * \param code the error code
             * \return NTW_ERROR_NO
             */
            static int msg(SocketSerialized& sock,const std::string message,unsigned int code);

            /**
             * \brief receive data from sock and check if
             * the message and code recv are the welcome one.
             * \param sock socket to check
             * \return the code recv
             */
            static int verifyIsConnected(SocketSerialized& sock);

            /**
             * \brief Regroup function for build a TCP server
             */
            class srv
            {
                public:
                    enum FUNCTONS_ID{UNKNOW=-1}; ///< Function namespace
                    static void dispatch(SocketSerialized& request); ///< call the dispatch(int,sock) function with the extracted id of function

                    /***
                     * \brief shortcut function to call a function.
                     * Exctact the param from the socket
                     * Note : sock format is <id|params ...>
                     * \param func the function to call
                     * \param sock the socket containing the param
                     * \return the func value
                     */
                    template<typename Ret,typename ... Args>
                    static Ret exec(Ret(*func)(SocketSerialized&,Args ...),SocketSerialized& sock);

                private:
                    srv() = delete;
                    srv& operator=(const srv&)=delete;
            };

            /**
             * \brief A class to help to build a TCP client
             */
            class cli
            {
                public:
                    /**
                     * \brief Call operator::<< on all args
                     * \param id the function id to call
                     * \param sock the socket used to store args
                     * \params args to copy in sock
                     */
                    template<typename ... Args>
                    static void addPackage(int id,SocketSerialized& sock,Args& ... args);

                    /**
                     * \brief Call operator<< on all args
                     * \param sock the socket used to store args
                     * \params args to copy in sock
                     */
                    template<typename T,typename ... Args>
                    static void addPackage(SocketSerialized& sock,T& a,Args& ... args);

                    /**
                     * \brief do nothing (for break template recurcivity)
                     */
                    static void addPackage(SocketSerialized& sock);

                    /**
                     * \brief call the function of id id on the server with param ... args
                     * \param sock the socket to use
                     * \param id the id function to call on the server
                     * \param args the args of the function to call
                     * \return the function called return value
                     */
                    template<typename Ret,typename ... Args>
                    static Ret send(SocketSerialized& sock,int id,Args&& ... args);

                private:
                    cli() = delete;
                    cli& operator=(const cli&) = delete;
            };
    };
};

#include <Socket/FuncWrapper.tpl>

#endif
<|endoftext|>


<commit_before>#ifndef INC_METTLE_COMPILED_SUITE_HPP
#define INC_METTLE_COMPILED_SUITE_HPP

#include <atomic>
#include <cstdint>
#include <functional>
#include <string>
#include <vector>

#include "attributes.hpp"

namespace mettle {

namespace detail {
  static inline uint64_t generate_id() {
    static std::atomic<uint64_t> id_(0);
    return id_++;
  }

  template<typename Container, typename Element>
  inline auto move_if(Element &&value) {
    using Value = typename std::remove_reference<Element>::type;
    using ReturnType = typename std::conditional<
      std::is_lvalue_reference<Container>::value, Value &, Value &&
    >::type;
    return static_cast<ReturnType>(value);
  }
}

struct test_result {
  bool passed;
  std::string message;
};

template<typename Ret, typename ...T>
class compiled_suite {
  template<typename Ret2, typename ...T2>
  friend class compiled_suite;
public:
  struct test_info {
    using function_type = std::function<Ret(T&...)>;

    test_info(std::string name, function_type function, attributes attrs)
      : name(std::move(name)), function(std::move(function)),
        attrs(std::move(attrs)), id(detail::generate_id()) {}

    std::string name;
    function_type function;
    attributes attrs;
    uint64_t id;
  };

  using iterator = typename std::vector<test_info>::const_iterator;

  template<typename String, typename Tests, typename Subsuites, typename Func>
  compiled_suite(
    String &&name, Tests &&tests, Subsuites &&subsuites,
    const attributes &attrs, const Func &f
  ) : name_(std::forward<String>(name)) {
    for(auto &&test : tests) {
      tests_.emplace_back(
        detail::move_if<Tests>(test.name),
        f(detail::move_if<Tests>(test.function)),
        unite(detail::move_if<Tests>(test.attrs), attrs)
      );
    }
    for(auto &&ss : subsuites)
      subsuites_.emplace_back(detail::move_if<Subsuites>(ss), attrs, f);
  }

  template<typename Ret2, typename ...T2, typename Func>
  compiled_suite(const compiled_suite<Ret2, T2...> &suite,
                 const attributes &attrs, const Func &f)
    : compiled_suite(suite.name_, suite.tests_, suite.subsuites_, attrs, f) {}

  template<typename Ret2, typename ...T2, typename Func>
  compiled_suite(compiled_suite<Ret2, T2...> &&suite,
                 const attributes &attrs, const Func &f)
    : compiled_suite(std::move(suite.name_), std::move(suite.tests_),
                     std::move(suite.subsuites_), attrs, f) {}

  const std::string & name() const {
    return name_;
  }

  iterator begin() const {
    return tests_.begin();
  }

  iterator end() const {
    return tests_.end();
  }

  size_t size() const {
    return tests_.size();
  }

  const std::vector<compiled_suite> & subsuites() const {
    return subsuites_;
  }
private:
  std::string name_;
  std::vector<test_info> tests_;
  std::vector<compiled_suite> subsuites_;
};

using runnable_suite = compiled_suite<test_result>;
using test_function = std::function<test_result(void)>;

} // namespace mettle

#endif
<commit_msg>Remove unnecessary "static"<commit_after>#ifndef INC_METTLE_COMPILED_SUITE_HPP
#define INC_METTLE_COMPILED_SUITE_HPP

#include <atomic>
#include <cstdint>
#include <functional>
#include <string>
#include <vector>

#include "attributes.hpp"

namespace mettle {

namespace detail {
  inline uint64_t generate_id() {
    static std::atomic<uint64_t> id_(0);
    return id_++;
  }

  template<typename Container, typename Element>
  inline auto move_if(Element &&value) {
    using Value = typename std::remove_reference<Element>::type;
    using ReturnType = typename std::conditional<
      std::is_lvalue_reference<Container>::value, Value &, Value &&
    >::type;
    return static_cast<ReturnType>(value);
  }
}

struct test_result {
  bool passed;
  std::string message;
};

template<typename Ret, typename ...T>
class compiled_suite {
  template<typename Ret2, typename ...T2>
  friend class compiled_suite;
public:
  struct test_info {
    using function_type = std::function<Ret(T&...)>;

    test_info(std::string name, function_type function, attributes attrs)
      : name(std::move(name)), function(std::move(function)),
        attrs(std::move(attrs)), id(detail::generate_id()) {}

    std::string name;
    function_type function;
    attributes attrs;
    uint64_t id;
  };

  using iterator = typename std::vector<test_info>::const_iterator;

  template<typename String, typename Tests, typename Subsuites, typename Func>
  compiled_suite(
    String &&name, Tests &&tests, Subsuites &&subsuites,
    const attributes &attrs, const Func &f
  ) : name_(std::forward<String>(name)) {
    for(auto &&test : tests) {
      tests_.emplace_back(
        detail::move_if<Tests>(test.name),
        f(detail::move_if<Tests>(test.function)),
        unite(detail::move_if<Tests>(test.attrs), attrs)
      );
    }
    for(auto &&ss : subsuites)
      subsuites_.emplace_back(detail::move_if<Subsuites>(ss), attrs, f);
  }

  template<typename Ret2, typename ...T2, typename Func>
  compiled_suite(const compiled_suite<Ret2, T2...> &suite,
                 const attributes &attrs, const Func &f)
    : compiled_suite(suite.name_, suite.tests_, suite.subsuites_, attrs, f) {}

  template<typename Ret2, typename ...T2, typename Func>
  compiled_suite(compiled_suite<Ret2, T2...> &&suite,
                 const attributes &attrs, const Func &f)
    : compiled_suite(std::move(suite.name_), std::move(suite.tests_),
                     std::move(suite.subsuites_), attrs, f) {}

  const std::string & name() const {
    return name_;
  }

  iterator begin() const {
    return tests_.begin();
  }

  iterator end() const {
    return tests_.end();
  }

  size_t size() const {
    return tests_.size();
  }

  const std::vector<compiled_suite> & subsuites() const {
    return subsuites_;
  }
private:
  std::string name_;
  std::vector<test_info> tests_;
  std::vector<compiled_suite> subsuites_;
};

using runnable_suite = compiled_suite<test_result>;
using test_function = std::function<test_result(void)>;

} // namespace mettle

#endif
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_STORAGE_HPP_INCLUDE
#define TORRENT_STORAGE_HPP_INCLUDE

#include <vector>
#include <bitset>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/limits.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/filesystem/path.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/torrent_info.hpp"
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/intrusive_ptr_base.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/config.hpp"

namespace libtorrent
{
	namespace aux
	{
		struct piece_checker_data;
	}

	namespace fs = boost::filesystem;

	class session;
	struct file_pool;
	struct disk_io_job;

	enum storage_mode_t
	{
		storage_mode_allocate = 0,
		storage_mode_sparse,
		storage_mode_compact
	};

#if defined(_WIN32) && defined(UNICODE)

	TORRENT_EXPORT std::wstring safe_convert(std::string const& s);

#endif

	TORRENT_EXPORT std::vector<std::pair<size_type, std::time_t> > get_filesizes(
		torrent_info const& t
		, fs::path p);

	TORRENT_EXPORT bool match_filesizes(
		torrent_info const& t
		, fs::path p
		, std::vector<std::pair<size_type, std::time_t> > const& sizes
		, bool compact_mode
		, std::string* error = 0);

	struct TORRENT_EXPORT file_allocation_failed: std::exception
	{
		file_allocation_failed(const char* error_msg): m_msg(error_msg) {}
		virtual const char* what() const throw() { return m_msg.c_str(); }
		virtual ~file_allocation_failed() throw() {}
		std::string m_msg;
	};

	struct TORRENT_EXPORT partial_hash
	{
		partial_hash(): offset(0) {}
		// the number of bytes in the piece that has been hashed
		int offset;
		// the sha-1 context
		hasher h;
	};

	struct TORRENT_EXPORT storage_interface
	{
		// create directories and set file sizes
		// if allocate_files is true.
		// allocate_files is true if allocation mode
		// is set to full and sparse files are supported
		virtual void initialize(bool allocate_files) = 0;

		// may throw file_error if storage for slot does not exist
		virtual size_type read(char* buf, int slot, int offset, int size) = 0;

		// may throw file_error if storage for slot hasn't been allocated
		virtual void write(const char* buf, int slot, int offset, int size) = 0;

		virtual bool move_storage(fs::path save_path) = 0;

		// verify storage dependent fast resume entries
		virtual bool verify_resume_data(entry& rd, std::string& error) = 0;

		// write storage dependent fast resume entries
		virtual void write_resume_data(entry& rd) const = 0;

		// moves (or copies) the content in src_slot to dst_slot
		virtual void move_slot(int src_slot, int dst_slot) = 0;

		// swaps the data in slot1 and slot2
		virtual void swap_slots(int slot1, int slot2) = 0;

		// swaps the puts the data in slot1 in slot2, the data in slot2
		// in slot3 and the data in slot3 in slot1
		virtual void swap_slots3(int slot1, int slot2, int slot3) = 0;

		// returns the sha1-hash for the data at the given slot
		virtual sha1_hash hash_for_slot(int slot, partial_hash& h, int piece_size) = 0;

		// this will close all open files that are opened for
		// writing. This is called when a torrent has finished
		// downloading.
		virtual void release_files() = 0;
		virtual ~storage_interface() {}
	};

	typedef storage_interface* (&storage_constructor_type)(
		boost::intrusive_ptr<torrent_info const>, fs::path const&
		, file_pool&);

	TORRENT_EXPORT storage_interface* default_storage_constructor(
		boost::intrusive_ptr<torrent_info const> ti
		, fs::path const& path, file_pool& fp);

	// returns true if the filesystem the path relies on supports
	// sparse files or automatic zero filling of files.
	TORRENT_EXPORT bool supports_sparse_files(fs::path const& p);

	struct disk_io_thread;

	class TORRENT_EXPORT piece_manager
		: public intrusive_ptr_base<piece_manager>
		, boost::noncopyable
	{
	friend class invariant_access;
	friend struct disk_io_thread;
	public:

		piece_manager(
			boost::shared_ptr<void> const& torrent
			, boost::intrusive_ptr<torrent_info const> ti
			, fs::path const& path
			, file_pool& fp
			, disk_io_thread& io
			, storage_constructor_type sc);

		~piece_manager();

		bool check_fastresume(aux::piece_checker_data& d
			, std::vector<bool>& pieces, int& num_pieces, storage_mode_t storage_mode
			, std::string& error_msg);
		std::pair<bool, float> check_files(std::vector<bool>& pieces
			, int& num_pieces, boost::recursive_mutex& mutex);

		// frees a buffer that was returned from a read operation
		void free_buffer(char* buf);

		void write_resume_data(entry& rd) const;
		bool verify_resume_data(entry& rd, std::string& error);

		bool is_allocating() const
		{ return m_state == state_expand_pieces; }

		void mark_failed(int index);

		unsigned long piece_crc(
			int slot_index
			, int block_size
			, piece_picker::block_info const* bi);

		int slot_for(int piece) const;
		int piece_for(int slot) const;

		void async_read(
			peer_request const& r
			, boost::function<void(int, disk_io_job const&)> const& handler
			, char* buffer = 0
			, int priority = 0);

		void async_write(
			peer_request const& r
			, char const* buffer
			, boost::function<void(int, disk_io_job const&)> const& f);

		void async_hash(int piece, boost::function<void(int, disk_io_job const&)> const& f);

		fs::path save_path() const;

		void async_release_files(
			boost::function<void(int, disk_io_job const&)> const& handler
			= boost::function<void(int, disk_io_job const&)>());

		void async_move_storage(fs::path const& p
			, boost::function<void(int, disk_io_job const&)> const& handler);

		// fills the vector that maps all allocated
		// slots to the piece that is stored (or
		// partially stored) there. -2 is the index
		// of unassigned pieces and -1 is unallocated
		void export_piece_map(std::vector<int>& pieces
			, std::vector<bool> const& have) const;

		bool compact_allocation() const
		{ return m_storage_mode == storage_mode_compact; }

#ifndef NDEBUG
		std::string name() const { return m_info->name(); }
#endif

	private:

		bool allocate_slots(int num_slots, bool abort_on_disk = false);

		int identify_data(
			const std::vector<char>& piece_data
			, int current_slot
			, std::vector<bool>& have_pieces
			, int& num_pieces
			, const std::multimap<sha1_hash, int>& hash_to_piece
			, boost::recursive_mutex& mutex);

		size_type read_impl(
			char* buf
			, int piece_index
			, int offset
			, int size);

		void write_impl(
			const char* buf
			, int piece_index
			, int offset
			, int size);

		void switch_to_full_mode();
		sha1_hash hash_for_piece_impl(int piece);

		void release_files_impl();

		bool move_storage_impl(fs::path const& save_path);

		int allocate_slot_for_piece(int piece_index);
#ifndef NDEBUG
		void check_invariant() const;
#ifdef TORRENT_STORAGE_DEBUG
		void debug_log() const;
#endif
#endif
		boost::scoped_ptr<storage_interface> m_storage;

		storage_mode_t m_storage_mode;

		// a bitmask representing the pieces we have
		std::vector<bool> m_have_piece;

		boost::intrusive_ptr<torrent_info const> m_info;

		// slots that haven't had any file storage allocated
		std::vector<int> m_unallocated_slots;
		// slots that have file storage, but isn't assigned to a piece
		std::vector<int> m_free_slots;

		enum
		{
			has_no_slot = -3 // the piece has no storage
		};

		// maps piece indices to slots. If a piece doesn't
		// have any storage, it is set to 'has_no_slot'
		std::vector<int> m_piece_to_slot;

		enum
		{
			unallocated = -1, // the slot is unallocated
			unassigned = -2   // the slot is allocated but not assigned to a piece
		};

		// maps slots to piece indices, if a slot doesn't have a piece
		// it can either be 'unassigned' or 'unallocated'
		std::vector<int> m_slot_to_piece;

		fs::path m_save_path;

		mutable boost::recursive_mutex m_mutex;

		enum {
			// the default initial state
			state_none,
			// the file checking is complete
			state_finished,
			// creating the directories
			state_create_files,
			// checking the files
			state_full_check,
			// move pieces to their final position
			state_expand_pieces
		} m_state;
		int m_current_slot;
		// used during check. If any piece is found
		// that is not in its final position, this
		// is set to true
		bool m_out_of_place;
		// used to move pieces while expanding
		// the storage from compact allocation
		// to full allocation
		std::vector<char> m_scratch_buffer;
		std::vector<char> m_scratch_buffer2;
		// the piece that is in the scratch buffer
		int m_scratch_piece;

		// this is saved in case we need to instantiate a new
		// storage (osed when remapping files)
		storage_constructor_type m_storage_constructor;

		// temporary buffer used while checking
		std::vector<char> m_piece_data;

		// this maps a piece hash to piece index. It will be
		// build the first time it is used (to save time if it
		// isn't needed)
		std::multimap<sha1_hash, int> m_hash_to_piece;

		// this map contains partial hashes for downloading
		// pieces. This is only accessed from within the
		// disk-io thread.
		std::map<int, partial_hash> m_piece_hasher;

		disk_io_thread& m_io_thread;

		// the reason for this to be a void pointer
		// is to avoid creating a dependency on the
		// torrent. This shared_ptr is here only
		// to keep the torrent object alive until
		// the piece_manager destructs. This is because
		// the torrent_info object is owned by the torrent.
		boost::shared_ptr<void> m_torrent;
	};

}

#endif // TORRENT_STORAGE_HPP_INCLUDED

<commit_msg>removed unused left-overs<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_STORAGE_HPP_INCLUDE
#define TORRENT_STORAGE_HPP_INCLUDE

#include <vector>
#include <bitset>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/limits.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/filesystem/path.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/torrent_info.hpp"
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/intrusive_ptr_base.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/config.hpp"

namespace libtorrent
{
	namespace aux
	{
		struct piece_checker_data;
	}

	namespace fs = boost::filesystem;

	class session;
	struct file_pool;
	struct disk_io_job;

	enum storage_mode_t
	{
		storage_mode_allocate = 0,
		storage_mode_sparse,
		storage_mode_compact
	};

#if defined(_WIN32) && defined(UNICODE)

	TORRENT_EXPORT std::wstring safe_convert(std::string const& s);

#endif

	TORRENT_EXPORT std::vector<std::pair<size_type, std::time_t> > get_filesizes(
		torrent_info const& t
		, fs::path p);

	TORRENT_EXPORT bool match_filesizes(
		torrent_info const& t
		, fs::path p
		, std::vector<std::pair<size_type, std::time_t> > const& sizes
		, bool compact_mode
		, std::string* error = 0);

	struct TORRENT_EXPORT file_allocation_failed: std::exception
	{
		file_allocation_failed(const char* error_msg): m_msg(error_msg) {}
		virtual const char* what() const throw() { return m_msg.c_str(); }
		virtual ~file_allocation_failed() throw() {}
		std::string m_msg;
	};

	struct TORRENT_EXPORT partial_hash
	{
		partial_hash(): offset(0) {}
		// the number of bytes in the piece that has been hashed
		int offset;
		// the sha-1 context
		hasher h;
	};

	struct TORRENT_EXPORT storage_interface
	{
		// create directories and set file sizes
		// if allocate_files is true.
		// allocate_files is true if allocation mode
		// is set to full and sparse files are supported
		virtual void initialize(bool allocate_files) = 0;

		// may throw file_error if storage for slot does not exist
		virtual size_type read(char* buf, int slot, int offset, int size) = 0;

		// may throw file_error if storage for slot hasn't been allocated
		virtual void write(const char* buf, int slot, int offset, int size) = 0;

		virtual bool move_storage(fs::path save_path) = 0;

		// verify storage dependent fast resume entries
		virtual bool verify_resume_data(entry& rd, std::string& error) = 0;

		// write storage dependent fast resume entries
		virtual void write_resume_data(entry& rd) const = 0;

		// moves (or copies) the content in src_slot to dst_slot
		virtual void move_slot(int src_slot, int dst_slot) = 0;

		// swaps the data in slot1 and slot2
		virtual void swap_slots(int slot1, int slot2) = 0;

		// swaps the puts the data in slot1 in slot2, the data in slot2
		// in slot3 and the data in slot3 in slot1
		virtual void swap_slots3(int slot1, int slot2, int slot3) = 0;

		// returns the sha1-hash for the data at the given slot
		virtual sha1_hash hash_for_slot(int slot, partial_hash& h, int piece_size) = 0;

		// this will close all open files that are opened for
		// writing. This is called when a torrent has finished
		// downloading.
		virtual void release_files() = 0;
		virtual ~storage_interface() {}
	};

	typedef storage_interface* (&storage_constructor_type)(
		boost::intrusive_ptr<torrent_info const>, fs::path const&
		, file_pool&);

	TORRENT_EXPORT storage_interface* default_storage_constructor(
		boost::intrusive_ptr<torrent_info const> ti
		, fs::path const& path, file_pool& fp);

	struct disk_io_thread;

	class TORRENT_EXPORT piece_manager
		: public intrusive_ptr_base<piece_manager>
		, boost::noncopyable
	{
	friend class invariant_access;
	friend struct disk_io_thread;
	public:

		piece_manager(
			boost::shared_ptr<void> const& torrent
			, boost::intrusive_ptr<torrent_info const> ti
			, fs::path const& path
			, file_pool& fp
			, disk_io_thread& io
			, storage_constructor_type sc);

		~piece_manager();

		bool check_fastresume(aux::piece_checker_data& d
			, std::vector<bool>& pieces, int& num_pieces, storage_mode_t storage_mode
			, std::string& error_msg);
		std::pair<bool, float> check_files(std::vector<bool>& pieces
			, int& num_pieces, boost::recursive_mutex& mutex);

		// frees a buffer that was returned from a read operation
		void free_buffer(char* buf);

		void write_resume_data(entry& rd) const;
		bool verify_resume_data(entry& rd, std::string& error);

		bool is_allocating() const
		{ return m_state == state_expand_pieces; }

		void mark_failed(int index);

		unsigned long piece_crc(
			int slot_index
			, int block_size
			, piece_picker::block_info const* bi);

		int slot_for(int piece) const;
		int piece_for(int slot) const;

		void async_read(
			peer_request const& r
			, boost::function<void(int, disk_io_job const&)> const& handler
			, char* buffer = 0
			, int priority = 0);

		void async_write(
			peer_request const& r
			, char const* buffer
			, boost::function<void(int, disk_io_job const&)> const& f);

		void async_hash(int piece, boost::function<void(int, disk_io_job const&)> const& f);

		fs::path save_path() const;

		void async_release_files(
			boost::function<void(int, disk_io_job const&)> const& handler
			= boost::function<void(int, disk_io_job const&)>());

		void async_move_storage(fs::path const& p
			, boost::function<void(int, disk_io_job const&)> const& handler);

		// fills the vector that maps all allocated
		// slots to the piece that is stored (or
		// partially stored) there. -2 is the index
		// of unassigned pieces and -1 is unallocated
		void export_piece_map(std::vector<int>& pieces
			, std::vector<bool> const& have) const;

		bool compact_allocation() const
		{ return m_storage_mode == storage_mode_compact; }

#ifndef NDEBUG
		std::string name() const { return m_info->name(); }
#endif

	private:

		bool allocate_slots(int num_slots, bool abort_on_disk = false);

		int identify_data(
			const std::vector<char>& piece_data
			, int current_slot
			, std::vector<bool>& have_pieces
			, int& num_pieces
			, const std::multimap<sha1_hash, int>& hash_to_piece
			, boost::recursive_mutex& mutex);

		size_type read_impl(
			char* buf
			, int piece_index
			, int offset
			, int size);

		void write_impl(
			const char* buf
			, int piece_index
			, int offset
			, int size);

		void switch_to_full_mode();
		sha1_hash hash_for_piece_impl(int piece);

		void release_files_impl();

		bool move_storage_impl(fs::path const& save_path);

		int allocate_slot_for_piece(int piece_index);
#ifndef NDEBUG
		void check_invariant() const;
#ifdef TORRENT_STORAGE_DEBUG
		void debug_log() const;
#endif
#endif
		boost::scoped_ptr<storage_interface> m_storage;

		storage_mode_t m_storage_mode;

		boost::intrusive_ptr<torrent_info const> m_info;

		// slots that haven't had any file storage allocated
		std::vector<int> m_unallocated_slots;
		// slots that have file storage, but isn't assigned to a piece
		std::vector<int> m_free_slots;

		enum
		{
			has_no_slot = -3 // the piece has no storage
		};

		// maps piece indices to slots. If a piece doesn't
		// have any storage, it is set to 'has_no_slot'
		std::vector<int> m_piece_to_slot;

		enum
		{
			unallocated = -1, // the slot is unallocated
			unassigned = -2   // the slot is allocated but not assigned to a piece
		};

		// maps slots to piece indices, if a slot doesn't have a piece
		// it can either be 'unassigned' or 'unallocated'
		std::vector<int> m_slot_to_piece;

		fs::path m_save_path;

		mutable boost::recursive_mutex m_mutex;

		enum {
			// the default initial state
			state_none,
			// the file checking is complete
			state_finished,
			// creating the directories
			state_create_files,
			// checking the files
			state_full_check,
			// move pieces to their final position
			state_expand_pieces
		} m_state;
		int m_current_slot;
		// used during check. If any piece is found
		// that is not in its final position, this
		// is set to true
		bool m_out_of_place;
		// used to move pieces while expanding
		// the storage from compact allocation
		// to full allocation
		std::vector<char> m_scratch_buffer;
		std::vector<char> m_scratch_buffer2;
		// the piece that is in the scratch buffer
		int m_scratch_piece;

		// this is saved in case we need to instantiate a new
		// storage (osed when remapping files)
		storage_constructor_type m_storage_constructor;

		// temporary buffer used while checking
		std::vector<char> m_piece_data;

		// this maps a piece hash to piece index. It will be
		// build the first time it is used (to save time if it
		// isn't needed)
		std::multimap<sha1_hash, int> m_hash_to_piece;

		// this map contains partial hashes for downloading
		// pieces. This is only accessed from within the
		// disk-io thread.
		std::map<int, partial_hash> m_piece_hasher;

		disk_io_thread& m_io_thread;

		// the reason for this to be a void pointer
		// is to avoid creating a dependency on the
		// torrent. This shared_ptr is here only
		// to keep the torrent object alive until
		// the piece_manager destructs. This is because
		// the torrent_info object is owned by the torrent.
		boost::shared_ptr<void> m_torrent;
	};

}

#endif // TORRENT_STORAGE_HPP_INCLUDED

<|endoftext|>


<commit_before>/** @file

  Multiplexes request to other origins.

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */
#include <inttypes.h>
#include <sys/time.h>

#include "dispatch.h"
#include "fetcher.h"
#include "original-request.h"

#ifndef PLUGIN_TAG
#error Please define a PLUGIN_TAG before including this file.
#endif

extern Statistics statistics;

extern size_t timeout;

Request::Request(const std::string &h, const TSMBuffer b, const TSMLoc l)
  : host(h), length(TSHttpHdrLengthGet(b, l)), io(new ats::io::IO())
{
  assert(!host.empty());
  assert(b != NULL);
  assert(l != NULL);
  assert(length > 0);
  assert(io.get() != NULL);
  TSHttpHdrPrint(b, l, io->buffer);
  assert(length == TSIOBufferReaderAvail(io->reader));
}

Request::Request(const Request &r) : host(r.host), length(r.length), io(const_cast<Request &>(r).io.release())
{
  assert(!host.empty());
  assert(length > 0);
  assert(io.get() != NULL);
  assert(r.io.get() != NULL);
}

Request &Request::operator=(const Request &r)
{
  host = r.host;
  length = r.length;
  io.reset(const_cast<Request &>(r).io.release());
  assert(!host.empty());
  assert(length > 0);
  assert(io.get() != NULL);
  assert(r.io.get() == NULL);
  return *this;
}

uint64_t
copy(const TSIOBufferReader &r, const TSIOBuffer b)
{
  assert(r != NULL);
  assert(b != NULL);
  TSIOBufferBlock block = TSIOBufferReaderStart(r);

  uint64_t length = 0;

  for (; block; block = TSIOBufferBlockNext(block)) {
    int64_t size = 0;
    const void *const pointer = TSIOBufferBlockReadStart(block, r, &size);

    if (pointer != NULL && size > 0) {
      const int64_t size2 = TSIOBufferWrite(b, pointer, size);
      assert(size == size2);
      length += size;
    }
  }

  return length;
}

uint64_t
read(const TSIOBufferReader &r, std::string &o, int64_t l = 0)
{
  assert(r != NULL);
  TSIOBufferBlock block = TSIOBufferReaderStart(r);

  assert(l >= 0);
  if (l == 0) {
    l = TSIOBufferReaderAvail(r);
    assert(l >= 0);
  }

  uint64_t length = 0;

  for (; block && l > 0; block = TSIOBufferBlockNext(block)) {
    int64_t size = 0;
    const char *const pointer = TSIOBufferBlockReadStart(block, r, &size);
    if (pointer != NULL && size > 0) {
      size = std::min(size, l);
      o.append(pointer, size);
      length += size;
      l -= size;
    }
  }

  return length;
}

uint64_t
read(const TSIOBuffer &b, std::string &o, const int64_t l = 0)
{
  TSIOBufferReader reader = TSIOBufferReaderAlloc(b);
  const uint64_t length = read(reader, o);
  TSIOBufferReaderFree(reader);
  return length;
}

class Handler
{
  int64_t length;
  struct timeval start;
  std::string response;

public:
  const std::string url;

  Handler(std::string u) : length(0)
  {
    assert(!u.empty());
    const_cast<std::string &>(url).swap(u);
    gettimeofday(&start, NULL);
  }

  void
  error(void)
  {
    TSError("[" PLUGIN_TAG "] error when communicating with \"%s\"\n", url.c_str());
    TSStatIntIncrement(statistics.failures, 1);
  }

  void
  timeout(void)
  {
    TSError("[" PLUGIN_TAG "] timeout when communicating with \"%s\"\n", url.c_str());
    TSStatIntIncrement(statistics.timeouts, 1);
  }

  void
  header(const TSMBuffer b, const TSMLoc l)
  {
    if (TSIsDebugTagSet(PLUGIN_TAG) > 0) {
      const TSIOBuffer buffer = TSIOBufferCreate();
      TSHttpHdrPrint(b, l, buffer);
      std::string b;
      read(buffer, b);
      TSDebug(PLUGIN_TAG, "Response header for \"%s\" was:\n%s", url.c_str(), b.c_str());
      TSIOBufferDestroy(buffer);
    }
  }

  void
  data(const TSIOBufferReader r, const int64_t l)
  {
    length += l;
    if (TSIsDebugTagSet(PLUGIN_TAG) > 0) {
      std::string buffer;
      const uint64_t length = read(r, buffer, l);
      response += buffer;
      TSDebug(PLUGIN_TAG, "Receiving response chunk \"%s\" of %" PRIu64 " bytes", buffer.c_str(), length);
    }
  }

  void
  done(void)
  {
    struct timeval end;

    gettimeofday(&end, NULL);

    if (TSIsDebugTagSet(PLUGIN_TAG) > 0) {
      TSDebug(PLUGIN_TAG, "Response for \"%s\" was:\n%s", url.c_str(), response.c_str());
    }

    const long diff = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);

    TSStatIntIncrement(statistics.hits, 1);
    TSStatIntIncrement(statistics.time, diff);
    TSStatIntIncrement(statistics.size, length);
  }
};

void
generateRequests(const Origins &o, const TSMBuffer buffer, const TSMLoc location, Requests &r)
{
  assert(!o.empty());
  assert(buffer != NULL);
  assert(location != NULL);

  Origins::const_iterator iterator = o.begin();
  const Origins::const_iterator end = o.end();

  OriginalRequest request(buffer, location);
  request.urlScheme("");
  request.urlHost("");
  request.xMultiplexerHeader("copy");

  for (; iterator != end; ++iterator) {
    const std::string &host = *iterator;
    assert(!host.empty());
    request.hostHeader(host);
    r.push_back(Request(host, buffer, location));
  }
}

void
addBody(Requests &r, const TSIOBufferReader re)
{
  assert(re != NULL);
  Requests::iterator iterator = r.begin();
  const Requests::iterator end = r.end();
  const int64_t length = TSIOBufferReaderAvail(re);
  if (length == 0) {
    return;
  }
  assert(length > 0);
  for (; iterator != end; ++iterator) {
    assert(iterator->io.get() != NULL);
    const int64_t size = copy(re, iterator->io->buffer);
    assert(size == length);
    iterator->length += size;
  }
}

void
dispatch(Requests &r, const int t)
{
  Requests::iterator iterator = r.begin();
  const Requests::iterator end = r.end();
  for (; iterator != end; ++iterator) {
    assert(iterator->io.get() != NULL);
    if (TSIsDebugTagSet(PLUGIN_TAG) > 0) {
      TSDebug(PLUGIN_TAG, "Dispatching %i bytes to \"%s\"", iterator->length, iterator->host.c_str());
      std::string b;
      read(iterator->io->reader, b);
      assert(b.size() == static_cast<uint64_t>(iterator->length));
      TSDebug(PLUGIN_TAG, "%s", b.c_str());
    }
    // forwarding iterator->io pointer ownership
    ats::get(iterator->io.release(), iterator->length, Handler(iterator->host), t);
  }
}
<commit_msg>[TS-4091] addressing internal headers This close #387.<commit_after>/** @file

  Multiplexes request to other origins.

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */
#include <inttypes.h>
#include <sys/time.h>

#include "dispatch.h"
#include "fetcher.h"
#include "original-request.h"

#ifndef PLUGIN_TAG
#error Please define a PLUGIN_TAG before including this file.
#endif

extern Statistics statistics;

extern size_t timeout;

Request::Request(const std::string &h, const TSMBuffer b, const TSMLoc l) : host(h), length(0), io(new ats::io::IO())
{
  assert(!host.empty());
  assert(b != NULL);
  assert(l != NULL);
  assert(io.get() != NULL);
  TSHttpHdrPrint(b, l, io->buffer);
  length = TSIOBufferReaderAvail(io->reader);
  assert(length > 0);
  /*
   * TSHttpHdrLengthGet returns the size with possible "internal" headers
   * which are not printed by TSHttpHdrPrint.
   * Therefore the greater than or equal comparisson
  */
  assert(TSHttpHdrLengthGet(b, l) >= length);
}

Request::Request(const Request &r) : host(r.host), length(r.length), io(const_cast<Request &>(r).io.release())
{
  assert(!host.empty());
  assert(length > 0);
  assert(io.get() != NULL);
  assert(r.io.get() != NULL);
}

Request &Request::operator=(const Request &r)
{
  host = r.host;
  length = r.length;
  io.reset(const_cast<Request &>(r).io.release());
  assert(!host.empty());
  assert(length > 0);
  assert(io.get() != NULL);
  assert(r.io.get() == NULL);
  return *this;
}

uint64_t
copy(const TSIOBufferReader &r, const TSIOBuffer b)
{
  assert(r != NULL);
  assert(b != NULL);
  TSIOBufferBlock block = TSIOBufferReaderStart(r);

  uint64_t length = 0;

  for (; block; block = TSIOBufferBlockNext(block)) {
    int64_t size = 0;
    const void *const pointer = TSIOBufferBlockReadStart(block, r, &size);

    if (pointer != NULL && size > 0) {
      const int64_t size2 = TSIOBufferWrite(b, pointer, size);
      assert(size == size2);
      length += size;
    }
  }

  return length;
}

uint64_t
read(const TSIOBufferReader &r, std::string &o, int64_t l = 0)
{
  assert(r != NULL);
  TSIOBufferBlock block = TSIOBufferReaderStart(r);

  assert(l >= 0);
  if (l == 0) {
    l = TSIOBufferReaderAvail(r);
    assert(l >= 0);
  }

  uint64_t length = 0;

  for (; block && l > 0; block = TSIOBufferBlockNext(block)) {
    int64_t size = 0;
    const char *const pointer = TSIOBufferBlockReadStart(block, r, &size);
    if (pointer != NULL && size > 0) {
      size = std::min(size, l);
      o.append(pointer, size);
      length += size;
      l -= size;
    }
  }

  return length;
}

uint64_t
read(const TSIOBuffer &b, std::string &o, const int64_t l = 0)
{
  TSIOBufferReader reader = TSIOBufferReaderAlloc(b);
  const uint64_t length = read(reader, o);
  TSIOBufferReaderFree(reader);
  return length;
}

class Handler
{
  int64_t length;
  struct timeval start;
  std::string response;

public:
  const std::string url;

  Handler(std::string u) : length(0)
  {
    assert(!u.empty());
    const_cast<std::string &>(url).swap(u);
    gettimeofday(&start, NULL);
  }

  void
  error(void)
  {
    TSError("[" PLUGIN_TAG "] error when communicating with \"%s\"\n", url.c_str());
    TSStatIntIncrement(statistics.failures, 1);
  }

  void
  timeout(void)
  {
    TSError("[" PLUGIN_TAG "] timeout when communicating with \"%s\"\n", url.c_str());
    TSStatIntIncrement(statistics.timeouts, 1);
  }

  void
  header(const TSMBuffer b, const TSMLoc l)
  {
    if (TSIsDebugTagSet(PLUGIN_TAG) > 0) {
      const TSIOBuffer buffer = TSIOBufferCreate();
      TSHttpHdrPrint(b, l, buffer);
      std::string b;
      read(buffer, b);
      TSDebug(PLUGIN_TAG, "Response header for \"%s\" was:\n%s", url.c_str(), b.c_str());
      TSIOBufferDestroy(buffer);
    }
  }

  void
  data(const TSIOBufferReader r, const int64_t l)
  {
    length += l;
    if (TSIsDebugTagSet(PLUGIN_TAG) > 0) {
      std::string buffer;
      const uint64_t length = read(r, buffer, l);
      response += buffer;
      TSDebug(PLUGIN_TAG, "Receiving response chunk \"%s\" of %" PRIu64 " bytes", buffer.c_str(), length);
    }
  }

  void
  done(void)
  {
    struct timeval end;

    gettimeofday(&end, NULL);

    if (TSIsDebugTagSet(PLUGIN_TAG) > 0) {
      TSDebug(PLUGIN_TAG, "Response for \"%s\" was:\n%s", url.c_str(), response.c_str());
    }

    const long diff = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);

    TSStatIntIncrement(statistics.hits, 1);
    TSStatIntIncrement(statistics.time, diff);
    TSStatIntIncrement(statistics.size, length);
  }
};

void
generateRequests(const Origins &o, const TSMBuffer buffer, const TSMLoc location, Requests &r)
{
  assert(!o.empty());
  assert(buffer != NULL);
  assert(location != NULL);

  Origins::const_iterator iterator = o.begin();
  const Origins::const_iterator end = o.end();

  OriginalRequest request(buffer, location);
  request.urlScheme("");
  request.urlHost("");
  request.xMultiplexerHeader("copy");

  for (; iterator != end; ++iterator) {
    const std::string &host = *iterator;
    assert(!host.empty());
    request.hostHeader(host);
    r.push_back(Request(host, buffer, location));
  }
}

void
addBody(Requests &r, const TSIOBufferReader re)
{
  assert(re != NULL);
  Requests::iterator iterator = r.begin();
  const Requests::iterator end = r.end();
  const int64_t length = TSIOBufferReaderAvail(re);
  if (length == 0) {
    return;
  }
  assert(length > 0);
  for (; iterator != end; ++iterator) {
    assert(iterator->io.get() != NULL);
    const int64_t size = copy(re, iterator->io->buffer);
    assert(size == length);
    iterator->length += size;
  }
}

void
dispatch(Requests &r, const int t)
{
  Requests::iterator iterator = r.begin();
  const Requests::iterator end = r.end();
  for (; iterator != end; ++iterator) {
    assert(iterator->io.get() != NULL);
    if (TSIsDebugTagSet(PLUGIN_TAG) > 0) {
      TSDebug(PLUGIN_TAG, "Dispatching %i bytes to \"%s\"", iterator->length, iterator->host.c_str());
      std::string b;
      read(iterator->io->reader, b);
      assert(b.size() == static_cast<uint64_t>(iterator->length));
      TSDebug(PLUGIN_TAG, "%s", b.c_str());
    }
    // forwarding iterator->io pointer ownership
    ats::get(iterator->io.release(), iterator->length, Handler(iterator->host), t);
  }
}
<|endoftext|>