<commit_before>#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <pcl_ros/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include "mongodb_store/SetParam.h"

#include <actionlib/server/simple_action_server.h>
#include <calibrate_chest/CalibrateCameraAction.h>

class CalibrateCameraServer {
private:

    bool do_calibrate; // register and unregister instead
    ros::NodeHandle n;
    actionlib::SimpleActionServer<calibrate_chest::CalibrateCameraAction> server;
    std::string action_name;
    ros::ServiceClient client;
    ros::Subscriber sub;
    std::string camera_topic;
    calibrate_chest::CalibrateCameraFeedback feedback;
    calibrate_chest::CalibrateCameraResult result;

public:

    CalibrateCameraServer(const std::string& name, const std::string& camera_name) :
        do_calibrate(false),
        server(n, name, boost::bind(&CalibrateCameraServer::execute_cb, this, _1), false),
        action_name(name),
        client(n.serviceClient<mongodb_store::SetParam>("/config_manager/set_param")),
        camera_topic(camera_name + "/depth/points")
    {
        sub = n.subscribe(camera_topic, 1, &CalibrateCameraServer::msg_callback, this);
        server.start();
    }

private:

    bool is_inlier(const Eigen::Vector3f& point, const Eigen::Vector4f plane, double threshold) const
    {
        return fabs(point.dot(plane.segment<3>(0)) + plane(3)) < threshold;
    }

    void plot_best_plane(const pcl::PointCloud<pcl::PointXYZ>& points, const Eigen::Vector4f plane, double threshold) const
    {
        pcl::PointCloud<pcl::PointXYZ>::Ptr inlier_cloud(new pcl::PointCloud<pcl::PointXYZ>());
        pcl::PointCloud<pcl::PointXYZ>::Ptr outlier_cloud(new pcl::PointCloud<pcl::PointXYZ>());

        for (int i = 0; i < points.size(); ++i) {
            if (is_inlier(points[i].getVector3fMap(), plane, threshold)) {
                inlier_cloud->push_back(points[i]);
            }
            else {
                outlier_cloud->push_back(points[i]);
            }
        }

        pcl::visualization::PCLVisualizer viewer("3D Viewer");
        viewer.setBackgroundColor(0, 0, 0);
        viewer.addCoordinateSystem(1.0);
        viewer.initCameraParameters();

        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> inlier_color_handler(inlier_cloud, 255, 0, 0);
        viewer.addPointCloud(inlier_cloud, inlier_color_handler, "inliers");

        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> outlier_color_handler(outlier_cloud, 0, 0, 255);
        viewer.addPointCloud(outlier_cloud, outlier_color_handler, "outliers");

        while (!viewer.wasStopped())
        {
            viewer.spinOnce(100);
            boost::this_thread::sleep(boost::posix_time::microseconds(100000));
        }

    }

    void compute_plane(Eigen::Vector4f& plane, const pcl::PointCloud<pcl::PointXYZ>& points, int* inds) const
    {
        Eigen::Vector3f first = points[inds[1]].getVector3fMap() - points[inds[0]].getVector3fMap();
        Eigen::Vector3f second = points[inds[2]].getVector3fMap() - points[inds[0]].getVector3fMap();
        Eigen::Vector3f normal = first.cross(second);
        normal.normalize();
        plane.segment<3>(0) = normal;
        plane(3) = -normal.dot(points[inds[0]].getVector3fMap());
    }

    void extract_height_and_angle(const Eigen::Vector4f& plane)
    {
        feedback.status = "Checking and saving calibration...";
        server.publishFeedback(feedback);

        ROS_INFO("Ground plane: %f, %f, %f, %f", plane(0), plane(1), plane(2), plane(3));
        double dist = fabs(plane(3)/plane(2)); // distance along z axis
        double height = fabs(plane(3)/plane.segment<3>(0).squaredNorm()); // height
        ROS_INFO("Distance to plane along camera axis: %f", dist);
        ROS_INFO("Height above ground: %f", height);
        double angle = asin(height/dist);
        double angle_deg = 180.0f*angle/M_PI;
        ROS_INFO("Angle radians: %f", angle);
        ROS_INFO("Angle degrees: %f", angle_deg);

        result.angle = angle_deg;
        result.height = height;

        if (fabs(45.0f - angle_deg) > 3.0f) {
            result.status = "Angle not close enough to 45 degrees.";
            server.setAborted(result);
            return;
        }

        mongodb_store::SetParam srv;
        char buffer[250];

        // store height above ground in datacentre
        ros::param::set("/chest_xtion_height", height);
        sprintf(buffer, "{\"path\":\"/chest_xtion_height\",\"value\":%f}", height);
        srv.request.param = buffer;
        if (!client.call(srv)) {
            ROS_ERROR("Failed to call set height, is config manager running?");
        }

        // store angle between camera and horizontal plane
        ros::param::set("/chest_xtion_angle", angle);
        sprintf(buffer, "{\"path\":\"/chest_xtion_angle\",\"value\":%f}", angle);
        srv.request.param = buffer;
        if (!client.call(srv)) {
            ROS_ERROR("Failed to call set angle, is config manager running?");
        }

        result.status = "Successfully computed and saved calibration.";
        server.setSucceeded(result);
    }

public:

    void msg_callback(const sensor_msgs::PointCloud2::ConstPtr& msg)
    {
        if (!do_calibrate) {
            return;
        }
        do_calibrate = false;

        feedback.status = "Calibrating...";
        feedback.progress = 0.0f;
        server.publishFeedback(feedback);

        ROS_INFO("Got a pointcloud, calibrating...");
        pcl::PointCloud<pcl::PointXYZ> cloud;
        pcl::fromROSMsg(*msg, cloud);

        int nbr = cloud.size();

        int max = 1000; // ransac iterations
        double threshold = 0.02; // threshold for plane inliers

        Eigen::Vector4f best_plane; // best plane parameters found
        int best_inliers = -1; // best number of inliers

        int inds[3];

        Eigen::Vector4f plane;
        int inliers;
        for (int i = 0; i < max; ++i) {

            for (int j = 0; j < 3; ++j) {
                inds[j] = rand() % nbr; // get a random point
            }

            // check that the points aren't the same
            if (inds[0] == inds[1] || inds[0] == inds[2] || inds[1] == inds[2]) {
                continue;
            }

            compute_plane(plane, cloud, inds);
            inliers = 0;
            for (int j = 0; j < nbr; j += 30) { // count number of inliers
                if (is_inlier(cloud[j].getVector3fMap(), plane, threshold)) {
                    ++inliers;
                }
            }

            if (inliers > best_inliers) {
                best_plane = plane;
                best_inliers = inliers;
                feedback.progress = float(i+1)/float(max);
                server.publishFeedback(feedback);
            }
        }

        extract_height_and_angle(best_plane); // find parameters and feed them to datacentre
        //plot_best_plane(cloud, best_plane, threshold); // visually evaluate plane fit
    }

    void execute_cb(const calibrate_chest::CalibrateCameraGoalConstPtr& goal)
    {
        if (goal->command == "calibrate") {
            do_calibrate = true;
        }
        else {
            result.status = "Enter command \"calibrate\" or \"publish\".";
            server.setAborted(result);
        }
    }
};

int main(int argc, char** argv)
{
    ros::init(argc, argv, "calibrate_chest");
    CalibrateCameraServer calibrate(ros::this_node::getName(), "chest_xtion");
    ros::spin();

	return 0;
}
<commit_msg>Made it a bit nicer<commit_after>#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <pcl_ros/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include "mongodb_store/SetParam.h"

#include <actionlib/server/simple_action_server.h>
#include <calibrate_chest/CalibrateCameraAction.h>

class CalibrateCameraServer {
private:

    //bool do_calibrate; // register and unregister instead
    ros::NodeHandle n;
    actionlib::SimpleActionServer<calibrate_chest::CalibrateCameraAction> server;
    std::string action_name;
    ros::ServiceClient client;
    //ros::Subscriber sub;
    std::string camera_topic;
    calibrate_chest::CalibrateCameraFeedback feedback;
    calibrate_chest::CalibrateCameraResult result;

public:

    CalibrateCameraServer(const std::string& name, const std::string& camera_name) :
        //do_calibrate(false),
        server(n, name, boost::bind(&CalibrateCameraServer::execute_cb, this, _1), false),
        action_name(name),
        client(n.serviceClient<mongodb_store::SetParam>("/config_manager/set_param")),
        camera_topic(camera_name + "/depth/points")
    {
        //sub = n.subscribe(camera_topic, 1, &CalibrateCameraServer::msg_callback, this);
        server.start();
    }

private:

    bool is_inlier(const Eigen::Vector3f& point, const Eigen::Vector4f plane, double threshold) const
    {
        return fabs(point.dot(plane.segment<3>(0)) + plane(3)) < threshold;
    }

    void plot_best_plane(const pcl::PointCloud<pcl::PointXYZ>& points, const Eigen::Vector4f plane, double threshold) const
    {
        pcl::PointCloud<pcl::PointXYZ>::Ptr inlier_cloud(new pcl::PointCloud<pcl::PointXYZ>());
        pcl::PointCloud<pcl::PointXYZ>::Ptr outlier_cloud(new pcl::PointCloud<pcl::PointXYZ>());

        for (int i = 0; i < points.size(); ++i) {
            if (is_inlier(points[i].getVector3fMap(), plane, threshold)) {
                inlier_cloud->push_back(points[i]);
            }
            else {
                outlier_cloud->push_back(points[i]);
            }
        }

        pcl::visualization::PCLVisualizer viewer("3D Viewer");
        viewer.setBackgroundColor(0, 0, 0);
        viewer.addCoordinateSystem(1.0);
        viewer.initCameraParameters();

        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> inlier_color_handler(inlier_cloud, 255, 0, 0);
        viewer.addPointCloud(inlier_cloud, inlier_color_handler, "inliers");

        pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> outlier_color_handler(outlier_cloud, 0, 0, 255);
        viewer.addPointCloud(outlier_cloud, outlier_color_handler, "outliers");

        while (!viewer.wasStopped())
        {
            viewer.spinOnce(100);
            boost::this_thread::sleep(boost::posix_time::microseconds(100000));
        }

    }

    void compute_plane(Eigen::Vector4f& plane, const pcl::PointCloud<pcl::PointXYZ>& points, int* inds) const
    {
        Eigen::Vector3f first = points[inds[1]].getVector3fMap() - points[inds[0]].getVector3fMap();
        Eigen::Vector3f second = points[inds[2]].getVector3fMap() - points[inds[0]].getVector3fMap();
        Eigen::Vector3f normal = first.cross(second);
        normal.normalize();
        plane.segment<3>(0) = normal;
        plane(3) = -normal.dot(points[inds[0]].getVector3fMap());
    }

    void extract_height_and_angle(const Eigen::Vector4f& plane)
    {
        feedback.status = "Checking and saving calibration...";
        server.publishFeedback(feedback);

        ROS_INFO("Ground plane: %f, %f, %f, %f", plane(0), plane(1), plane(2), plane(3));
        double dist = fabs(plane(3)/plane(2)); // distance along z axis
        double height = fabs(plane(3)/plane.segment<3>(0).squaredNorm()); // height
        ROS_INFO("Distance to plane along camera axis: %f", dist);
        ROS_INFO("Height above ground: %f", height);
        double angle = asin(height/dist);
        double angle_deg = 180.0f*angle/M_PI;
        ROS_INFO("Angle radians: %f", angle);
        ROS_INFO("Angle degrees: %f", angle_deg);

        result.angle = angle_deg;
        result.height = height;

        if (fabs(45.0f - angle_deg) > 3.0f) {
            result.status = "Angle not close enough to 45 degrees.";
            server.setAborted(result);
            return;
        }

        mongodb_store::SetParam srv;
        char buffer[250];

        // store height above ground in datacentre
        ros::param::set("/chest_xtion_height", height);
        sprintf(buffer, "{\"path\":\"/chest_xtion_height\",\"value\":%f}", height);
        srv.request.param = buffer;
        if (!client.call(srv)) {
            ROS_ERROR("Failed to call set height, is config manager running?");
        }

        // store angle between camera and horizontal plane
        ros::param::set("/chest_xtion_angle", angle);
        sprintf(buffer, "{\"path\":\"/chest_xtion_angle\",\"value\":%f}", angle);
        srv.request.param = buffer;
        if (!client.call(srv)) {
            ROS_ERROR("Failed to call set angle, is config manager running?");
        }

        result.status = "Successfully computed and saved calibration.";
        server.setSucceeded(result);
    }

public:

    void msg_callback(const sensor_msgs::PointCloud2::ConstPtr& msg)
    {
        //if (!do_calibrate) {
        //    return;
        //}
        //do_calibrate = false;

        feedback.status = "Calibrating...";
        feedback.progress = 0.0f;
        server.publishFeedback(feedback);

        ROS_INFO("Got a pointcloud, calibrating...");
        pcl::PointCloud<pcl::PointXYZ> cloud;
        pcl::fromROSMsg(*msg, cloud);

        int nbr = cloud.size();

        int max = 1000; // ransac iterations
        double threshold = 0.02; // threshold for plane inliers

        Eigen::Vector4f best_plane; // best plane parameters found
        int best_inliers = -1; // best number of inliers

        int inds[3];

        Eigen::Vector4f plane;
        int inliers;
        for (int i = 0; i < max; ++i) {

            for (int j = 0; j < 3; ++j) {
                inds[j] = rand() % nbr; // get a random point
            }

            // check that the points aren't the same
            if (inds[0] == inds[1] || inds[0] == inds[2] || inds[1] == inds[2]) {
                continue;
            }

            compute_plane(plane, cloud, inds);
            inliers = 0;
            for (int j = 0; j < nbr; j += 30) { // count number of inliers
                if (is_inlier(cloud[j].getVector3fMap(), plane, threshold)) {
                    ++inliers;
                }
            }

            if (inliers > best_inliers) {
                best_plane = plane;
                best_inliers = inliers;
                feedback.progress = float(i+1)/float(max);
                server.publishFeedback(feedback);
            }
        }

        extract_height_and_angle(best_plane); // find parameters and feed them to datacentre
        //plot_best_plane(cloud, best_plane, threshold); // visually evaluate plane fit
    }

    void execute_cb(const calibrate_chest::CalibrateCameraGoalConstPtr& goal)
    {
        if (goal->command == "calibrate") {
            sensor_msgs::PointCloud2::ConstPtr msg = ros::topic::waitForMessage<sensor_msgs::PointCloud2>(camera_topic, n);
            if (msg) {
                msg_callback(msg);
            }
            else {
                result.status = "Did not receive any point cloud.";
                server.setAborted(result);
            }
        }
        else {
            result.status = "Enter command \"calibrate\" or \"publish\".";
            server.setAborted(result);
        }
    }
};

int main(int argc, char** argv)
{
    ros::init(argc, argv, "calibrate_chest");
    CalibrateCameraServer calibrate(ros::this_node::getName(), "chest_xtion");
    ros::spin();

	return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>

#include "pixelboost/data/xml/xml.h"

#include "hlsl2glsl.h"
#include "src/glsl/glsl_optimizer.h"

enum ShaderPlatform
{
    kShaderPlatformGLES,
    kShaderPlatformD3D9,
    kShaderPlatformOpenGL2,
};

bool CompileShader(ShaderPlatform platform, std::string input, std::string entry, std::string& output)
{
    if (platform == kShaderPlatformGLES)
    {
        // Compile Cg to GLSL and optimize

        ShHandle handle = Hlsl2Glsl_ConstructCompiler(EShLangVertex);

        Hlsl2Glsl_Parse(handle, input.c_str(), ETranslateOpUsePrecision);

        Hlsl2Glsl_UseUserVaryings(handle, true);

        EAttribSemantic semanticEnums[] = {EAttrSemPosition, EAttrSemColor0, EAttrSemColor1};
        const char* semanticNames[] = {"position", "colora", "colorb"};

        Hlsl2Glsl_SetUserAttributeNames(handle, semanticEnums, semanticNames, 2);

        Hlsl2Glsl_Translate(handle, entry.c_str(), ETranslateOpUsePrecision);

        const char* shader = Hlsl2Glsl_GetShader(handle);

        output = shader;

        Hlsl2Glsl_DestructCompiler(handle);

        glslopt_ctx* ctx = glslopt_initialize(true);

        glslopt_shader* optimisedShader = glslopt_optimize(ctx, kGlslOptShaderVertex, output.c_str(), 0);
        if (glslopt_get_status(optimisedShader)) {
            output = glslopt_get_output(optimisedShader);
        } else {
            printf("Error: %s\n", glslopt_get_log(optimisedShader));
        }
        glslopt_shader_delete(optimisedShader);

        glslopt_cleanup (ctx);

        return false;
    } else {
        // Compile using CGC

        fflush(0);

        char tempFilename[L_tmpnam];

        tmpnam(tempFilename);

        std::string command = "cgc -entry " + entry + " " + tempFilename;

        FILE* shaderFile = fopen(tempFilename, "w");

        fputs(input.c_str(), shaderFile);

        fclose(shaderFile);

        system(command.c_str());
    }

    return true;
}

int main(int argc, const char * argv[])
{
    std::string shader;

    std::string input = "";

    Hlsl2Glsl_Initialize();

    CompileShader(kShaderPlatformGLES, input, "", shader);

    Hlsl2Glsl_Finalize();

    printf("%s\n", shader.c_str());

    return 0;
}

<commit_msg>Compile both vertex and fragment shaders<commit_after>#include <iostream>
#include <string>

#include "pixelboost/data/xml/xml.h"

#include "hlsl2glsl.h"
#include "src/glsl/glsl_optimizer.h"

enum ShaderPlatform
{
    kShaderPlatformGLES,
    kShaderPlatformD3D9_SM2,
    kShaderPlatformD3D9_SM3,
    kShaderPlatformOpenGL2,
};

enum ShaderType
{
    kShaderTypeVertex,
    kShaderTypeFragment,
};

bool CompileShaderGLES(ShaderType type, const std::string& input, const std::string& entry, std::string& output)
{
    // Compile Cg to GLSL and optimize

    ShHandle handle = Hlsl2Glsl_ConstructCompiler(type == kShaderTypeVertex ? EShLangVertex : EShLangFragment);

    Hlsl2Glsl_Parse(handle, input.c_str(), ETranslateOpUsePrecision);

    Hlsl2Glsl_UseUserVaryings(handle, true);

    EAttribSemantic semanticEnums[] = {EAttrSemPosition, EAttrSemBinormal, EAttrSemNormal, EAttrSemColor0, EAttrSemColor1};
    const char* semanticNames[] = {"position", "binormal", "normal", "colora", "colorb"};

    Hlsl2Glsl_SetUserAttributeNames(handle, semanticEnums, semanticNames, 5);

    Hlsl2Glsl_Translate(handle, entry.c_str(), ETranslateOpUsePrecision);

    const char* shader = Hlsl2Glsl_GetShader(handle);

    output = shader;

    Hlsl2Glsl_DestructCompiler(handle);

    glslopt_ctx* ctx = glslopt_initialize(true);

    glslopt_shader* optimisedShader = glslopt_optimize(ctx, type == kShaderTypeVertex ? kGlslOptShaderVertex : kGlslOptShaderFragment, output.c_str(), 0);
    if (glslopt_get_status(optimisedShader)) {
        output = glslopt_get_output(optimisedShader);
    } else {
        printf("Error: %s\n", glslopt_get_log(optimisedShader));
        return false;
    }
    glslopt_shader_delete(optimisedShader);

    glslopt_cleanup (ctx);

    return true;
}

bool CompileShaderCGC(ShaderPlatform platform, ShaderType type, const std::string& input, const std::string& entry, std::string& output)
{
    fflush(0);

    char tempFilename[L_tmpnam];

    tmpnam(tempFilename);

    std::string profile;

    switch (platform)
    {
        case kShaderPlatformOpenGL2:
            profile = type == kShaderTypeVertex ? "arbvp1" : "arbfp1";
            break;
        case kShaderPlatformD3D9_SM2:
            profile = type == kShaderTypeVertex ? "vs_2_0" : "ps_2_0";
            break;
        case kShaderPlatformD3D9_SM3:
            profile = type == kShaderTypeVertex ? "vs_3_0" : "ps_3_0";
            break;
        case kShaderPlatformGLES:
            break;
    }

    FILE* shaderFile = fopen(tempFilename, "w");

    fputs(input.c_str(), shaderFile);

    fclose(shaderFile);

    std::string command = "cgc -entry " + entry + " -profile " + profile + " " + tempFilename + " 2>0";

    FILE* cgcOutput = popen(command.c_str(), "r");

    char buffer[1024];
    while (char* line = fgets(buffer, sizeof(buffer), cgcOutput))
    {
        output += line;
    }

    pclose(cgcOutput);

    remove(tempFilename);

    return true;
}

bool CompileShader(ShaderPlatform platform, const std::string& input, const std::string& vertexEntry, const std::string& fragmentEntry, std::string& vertex, std::string& fragment)
{
    bool status = true;

    if (platform == kShaderPlatformGLES)
    {
        status &= CompileShaderGLES(kShaderTypeVertex, input, vertexEntry, vertex);
        status &= CompileShaderGLES(kShaderTypeFragment, input, fragmentEntry, fragment);
    } else {
        status &= CompileShaderCGC(platform, kShaderTypeVertex, input, vertexEntry, vertex);
        status &= CompileShaderCGC(platform, kShaderTypeFragment, input, fragmentEntry, fragment);
    }

    return status;
}

int main(int argc, const char * argv[])
{
    std::string vertex, fragment;

    std::string input = "";

    std::string vertexEntry = "vert";
    std::string fragmentEntry = "frag";

    Hlsl2Glsl_Initialize();

    bool status = true;

    status &= CompileShader(kShaderPlatformOpenGL2, input, vertexEntry, fragmentEntry, vertex, fragment);

    Hlsl2Glsl_Finalize();

    if (!status)
        return 1;

    return 0;
}

<|endoftext|>


<commit_before>#include <fstream>

#include <chdl/chdl.h>
#include <chdl/cassign.h>

#include "config.h"
#include "interfaces.h"
#include "harpinst.h"

using namespace std;
using namespace chdl;

void PredRegs(pred_reg_t &out, fetch_pred_t &in, splitter_pred_t &wb);
void GpRegs(reg_func_t &out, pred_reg_t &in, splitter_reg_t &wb);

void PredRegs(pred_reg_t &out, fetch_pred_t &in, splitter_pred_t &wb) {
  HIERARCHY_ENTER();
  harpinst<N, RR, RR> inst(_(_(in, "contents"), "ir"));

  vec<W, vec<R, bvec<L> > > pregs;

  _(wb, "ready") = Lit(1);  // Always ready to accept writebacks.

  // Instantiate the registers
  for (unsigned w = 0; w < W; ++w) {
    for (unsigned r = 0; r < R; ++r) {
      for (unsigned l = 0; l < L; ++l) {
        node inMask(_(_(wb, "contents"), "mask")[l]),
             wSel(_(_(wb, "contents"), "wid") == Lit<WW>(w)),
    	     rSel(_(_(wb, "contents"), "dest") == Lit<RR>(r)),
  	     wr(inMask && rSel && wSel && _(wb, "valid"));
        pregs[w][r][l] = Wreg(wr, _(_(wb, "contents"), "val")[l]);
      }
    }
  }

  tap("pred_wb_wid", _(_(wb, "contents"), "wid"));

  // Handle ready and valid signals
  node ready(_(out, "ready"));
  _(in, "ready") = ready;
  _(out, "valid") = Wreg(ready, _(in, "valid"));
  _(_(out, "contents"), "warp") = Wreg(ready, _(_(in, "contents"), "warp"));
  _(_(out, "contents"), "ir") = Wreg(ready, _(_(in, "contents"), "ir"));

  bvec<WW> wid(_(_(_(in, "contents"), "warp"), "id"));

  bvec<L> pmask, pval0, pval1;

  // The mask should be all 1s if the instruction is not predicated.
  _(_(_(out, "contents"), "pval"), "pmask")
    = Wreg(ready, pmask | bvec<L>(!inst.has_pred()));

  _(_(_(out, "contents"), "pval"), "val0") = Wreg(ready, pval0);
  _(_(_(out, "contents"), "pval"), "val1") = Wreg(ready, pval1);

  pmask = Mux(inst.get_pred(), Mux(wid, pregs));
  pval0 = Mux(inst.get_psrc0(), Mux(wid, pregs));
  pval1 = Mux(inst.get_psrc1(), Mux(wid, pregs));

  TAP(pregs);

  HIERARCHY_EXIT();
}

void GpRegs(reg_func_t &out, pred_reg_t &in, splitter_reg_t &wb) {
  HIERARCHY_ENTER();
  harpinst<N, RR, RR> inst(_(_(in, "contents"), "ir"));

  vec<W, vec<L, vec<R, bvec<N> > > > regs;

  bvec<WW> wb_wid(_(_(wb, "contents"), "wid"));
  bvec<LL> wb_clonesrc(_(_(wb, "contents"), "clonesrc")),
           wb_clonedest(_(_(wb, "contents"), "clonedest"));
  vec<L, bvec<N> > wb_val(_(_(wb, "contents"), "val"));
  bvec<L> wbMask(_(_(wb, "contents"), "mask"));

  vec<R, bvec<N> > clonebus(Mux(wb_clonesrc, Mux(wb_wid, regs)));

  _(wb, "ready") = Lit(1); // Always ready to accept writebacks.

  // Instantiate the registers
  for (unsigned w = 0; w < W; ++w) {
    node destWarp(wb_wid == Lit<WW>(w));
    for (unsigned r = 0; r < R; ++r) {
      node destReg(_(_(wb, "contents"), "dest") == Lit<RR>(r));
      for (unsigned l = 0; l < L; ++l) {
        node clone(_(_(wb, "contents"), "clone") && Lit<LL>(l) == wb_clonedest),
             wr(destWarp && _(wb, "valid") && (clone || destReg && wbMask[l]));
        unsigned initVal(0);
        if (r == 0) initVal = l;
        else if (r == 1) initVal = w;
        regs[w][l][r] = Wreg(wr, Mux(clone, wb_val[l], clonebus[r]), initVal);
      }
    }
  }

  TAP(wb_wid);

  node ready(_(out, "ready"));
  bvec<WW> wid(_(_(_(in, "contents"), "warp"), "id"));

  vec<L, bvec<N> > rval0, rval1, rval2;

  // Get the register values
  for (unsigned l = 0; l < L; ++l) {
    rval0[l] = Mux(inst.get_rsrc0(), Mux(wid, regs)[l]);
    rval1[l] = Mux(inst.get_rsrc1(), Mux(wid, regs)[l]);
    rval2[l] = Mux(inst.get_rsrc2(), Mux(wid, regs)[l]);
  }

  _(in, "ready") = ready;
  _(out, "valid") = Wreg(ready, _(in, "valid"));
  _(_(out, "contents"), "warp") = Wreg(ready, _(_(in, "contents"), "warp"));
  _(_(out, "contents"), "ir") = Wreg(ready, _(_(in, "contents"), "ir"));
  _(_(out, "contents"), "pval") = Wreg(ready, _(_(in, "contents"), "pval"));
  Flatten(_(_(_(out,"contents"),"rval"),"val0")) = Wreg(ready, Flatten(rval0));
  Flatten(_(_(_(out,"contents"),"rval"),"val1")) = Wreg(ready, Flatten(rval1));
  Flatten(_(_(_(out,"contents"),"rval"),"val2")) = Wreg(ready, Flatten(rval2));

  TAP(regs);

  HIERARCHY_EXIT();
}
<commit_msg>SRAM-based register file.<commit_after>#include <fstream>

#include <chdl/chdl.h>
#include <chdl/cassign.h>

#include "config.h"
#include "interfaces.h"
#include "harpinst.h"

using namespace std;
using namespace chdl;

void PredRegs(pred_reg_t &out, fetch_pred_t &in, splitter_pred_t &wb);
void GpRegs(reg_func_t &out, pred_reg_t &in, splitter_reg_t &wb);

void PredRegs(pred_reg_t &out, fetch_pred_t &in, splitter_pred_t &wb) {
  HIERARCHY_ENTER();
  harpinst<N, RR, RR> inst(_(_(in, "contents"), "ir"));

  bvec<WW> wid(_(_(_(in, "contents"), "warp"), "id")),
           wb_wid(_(_(wb, "contents"), "wid"));

  bvec<WW + RR> a_ipred(Cat(wid, inst.get_pred())),
                a_src0 (Cat(wid, inst.get_psrc0())),
                a_src1 (Cat(wid, inst.get_psrc1())),
                a_wb   (Cat(wb_wid, _(_(wb, "contents"), "dest")));

  bvec<L> wb_mask(_(_(wb, "contents"), "mask") & bvec<L>(_(wb, "valid"))),
          wb_val(_(_(wb, "contents"), "val"));

  vec<3, bvec<WW + RR> > rd_addr;
  rd_addr[0] = a_ipred;
  rd_addr[1] = a_src0;
  rd_addr[2] = a_src1;

  vec<L, vec<3, bvec<1> > > q;

  for (unsigned i = 0; i < L; ++i)
    q[i] = Syncmem(rd_addr, bvec<1>(wb_val[i]), a_wb, wb_mask[i]);

  bvec<L> pval0, pval1, pmask;

  for (unsigned i = 0; i < L; ++i) {
    pmask[i] = q[i][0][0];
    pval0[i] = q[i][1][0];
    pval1[i] = q[i][2][0];
  }

  _(wb, "ready") = Lit(1);  // Always ready to accept writebacks.

  tap("pred_wb_wid", _(_(wb, "contents"), "wid"));

  // Handle ready and valid signals
  node ready(_(out, "ready"));
  _(in, "ready") = ready;
  _(out, "valid") = Wreg(ready, _(in, "valid"));
  _(_(out, "contents"), "warp") = Wreg(ready, _(_(in, "contents"), "warp"));
  _(_(out, "contents"), "ir") = Wreg(ready, _(_(in, "contents"), "ir"));

  // The mask should be all 1s if the instruction is not predicated.
  _(_(_(out, "contents"), "pval"), "pmask")
    = Latch(!ready, pmask | bvec<L>(Reg(!inst.has_pred())));

  _(_(_(out, "contents"), "pval"), "val0") = Latch(!ready, pval0);
  _(_(_(out, "contents"), "pval"), "val1") = Latch(!ready, pval1);

  HIERARCHY_EXIT();
}

void GpRegs(reg_func_t &out, pred_reg_t &in, splitter_reg_t &wb) {
  HIERARCHY_ENTER();
  harpinst<N, RR, RR> inst(_(_(in, "contents"), "ir"));

  bvec<RR> wb_dest(_(_(wb, "contents"), "dest"));
  bvec<WW> wid(_(_(_(in, "contents"), "warp"), "id")),
           wb_wid(_(_(wb, "contents"), "wid"));
  bvec<LL> wb_clonesrc(_(_(wb, "contents"), "clonesrc")),
           wb_clonedest(_(_(wb, "contents"), "clonedest"));
  vec<L, bvec<N> > wb_val(_(_(wb, "contents"), "val"));
  bvec<L> wbMask(_(_(wb, "contents"), "mask"));

  vec<R, bvec<N> > clonebus;

  _(wb, "ready") = Lit(1); // Always ready to accept writebacks.

  vec<L, bvec<N> > rval0, rval1, rval2;

  node clone(_(wb, "valid") && _(_(wb, "contents"), "clone"));
  bvec<L> wb_mask(_(_(wb, "contents"), "mask") &
                    bvec<L>(_(wb, "valid") && !clone));

  vec<L, vec<R, vec<2, bvec<N> > > > q;

  vec<2, bvec<WW> > a;
  a[0] = wid;
  a[1] = wb_wid;

  for (unsigned l = 0; l < L; ++l) {
    for (unsigned i = 0; i < R; ++i) {
      node wr(wb_mask[l] && wb_dest == Lit<RR>(i) ||
                wb_clonedest == Lit<LL>(i) && clone);
      q[l][i] = Syncmem(a, Mux(clone, wb_val[l], clonebus[i]), wb_wid, wr);
    }
  }

  for (unsigned i = 0; i < R; ++i) {
    vec<L, bvec<N> > cb_slice;
    for (unsigned l = 0; l < L; ++l)
      cb_slice[l] = q[l][i][1];
    clonebus[i] = Mux(wb_clonesrc, cb_slice);
  }

  for (unsigned l = 0; l < L; ++l) {
    rval0[l] = Mux(Reg(inst.get_rsrc0()), q[l])[0];
    rval1[l] = Mux(Reg(inst.get_rsrc1()), q[l])[0];
    rval2[l] = Mux(Reg(inst.get_rsrc2()), q[l])[0];
  }

  TAP(rval0);
  TAP(rval1);
  TAP(rval2);

  TAP(wb_wid);

  node ready(_(out, "ready"));

  _(in, "ready") = ready;
  _(out, "valid") = Wreg(ready, _(in, "valid"));
  _(_(out, "contents"), "warp") = Wreg(ready, _(_(in, "contents"), "warp"));
  _(_(out, "contents"), "ir") = Wreg(ready, _(_(in, "contents"), "ir"));
  _(_(out, "contents"), "pval") = Wreg(ready, _(_(in, "contents"), "pval"));
  Flatten(_(_(_(out,"contents"),"rval"),"val0")) = Latch(!ready,Flatten(rval0));
  Flatten(_(_(_(out,"contents"),"rval"),"val1")) = Latch(!ready,Flatten(rval1));
  Flatten(_(_(_(out,"contents"),"rval"),"val2")) = Latch(!ready,Flatten(rval2));

  HIERARCHY_EXIT();
}
<|endoftext|>


<commit_before>#include <ncurses.h>
#include <utility>

#include "board.hpp"
#include "enemy.hpp"
#include "log.hpp"
#include "print.hpp"
#include "reversi.hpp"

namespace roadagain
{

Reversi::Reversi(const CellColor& player, Level level) : player_(player), now_(CellColor::BLACK), next_(CellColor::WHITE)
{
    board_ = new Board();
    enemy_ = new Enemy(level);
    logs_ = new std::vector<Log>();
    logs_->reserve(Board::MAX_PUT);
}

Reversi::~Reversi()
{
    delete board_;
}

void Reversi::start() const
{
    board_->print();
}

void Reversi::play()
{
    start();

    for (int i = 0; i < Board::MAX_PUT; i++){
        if (not board_->can_put(now_)){
            change();
            if (not board_->can_put(now_)){
                break;
            }
        }
        Point p;
        if (now_ == player_){
            p = move();
        }
        else {
            p = enemy_->select(board_, now_);
            getch();
        }
        if (p.y == -1 && p.x == -1){
            break;
        }
        board_->put(Cell(p, now_));
        change();
        logs_->push_back(Log(p, now_));
    }
    end();
}

void Reversi::end() const
{
    CellColor winner = board_->winner();
    ::move(Board::END.y + 2, Board::START.x);
    switch (winner){
      case CellColor::BLACK:
        printw(" Winner is Black ");
        break;
      case CellColor::WHITE:
        printw(" Winner is White ");
        break;
      default:
        printw(" Draw ");
        break;
    }
    ::move(Board::END.y + 2, Board::END.x - 6);
    printw(" %02d %02d ", board_->black(), board_->white());
    log_records(*logs_, winner);
}

Point Reversi::move() const
{
    Point p;
    char c;

    if (board_->empty(p)){
        print_stone(p, now_);
    }
    else {
        print_coordinate(p);
    }

    c = getch();
    while (c != '\n' || not board_->can_put(p, now_)){
        if (board_->empty(p)){
            clear_stone(p);
        }
        else {
            clear_coordinate(p);
        }
        switch (c){
          case 'h':
            p.x = (p.x + Board::COL - 1) % Board::COL;
            break;
          case 'j':
            p.y = (p.y + 1) % Board::ROW;
            break;
          case 'k':
            p.y = (p.y + Board::ROW - 1) % Board::ROW;
            break;
          case 'l':
            p.x = (p.x + 1) % Board::COL;
            break;
          case ' ':
            return (Point(-1, -1));
        }
        if (board_->empty(p)){
            print_stone(p, now_);
        }
        else {
            print_coordinate(p);
        }
        c = getch();
    }
    clear_stone(p);

    return (p);
}

void Reversi::change()
{
    now_ = next_;
    next_.reverse();
}

} // namespace roadagain
<commit_msg>Free dynamic-obtained objects in Reversi's destructor<commit_after>#include <ncurses.h>
#include <utility>

#include "board.hpp"
#include "enemy.hpp"
#include "log.hpp"
#include "print.hpp"
#include "reversi.hpp"

namespace roadagain
{

Reversi::Reversi(const CellColor& player, Level level) : player_(player), now_(CellColor::BLACK), next_(CellColor::WHITE)
{
    board_ = new Board();
    enemy_ = new Enemy(level);
    logs_ = new std::vector<Log>();
    logs_->reserve(Board::MAX_PUT);
}

Reversi::~Reversi()
{
    delete board_;
    delete enemy_;
    delete logs_;
}

void Reversi::start() const
{
    board_->print();
}

void Reversi::play()
{
    start();

    for (int i = 0; i < Board::MAX_PUT; i++){
        if (not board_->can_put(now_)){
            change();
            if (not board_->can_put(now_)){
                break;
            }
        }
        Point p;
        if (now_ == player_){
            p = move();
        }
        else {
            p = enemy_->select(board_, now_);
            getch();
        }
        if (p.y == -1 && p.x == -1){
            break;
        }
        board_->put(Cell(p, now_));
        change();
        logs_->push_back(Log(p, now_));
    }
    end();
}

void Reversi::end() const
{
    CellColor winner = board_->winner();
    ::move(Board::END.y + 2, Board::START.x);
    switch (winner){
      case CellColor::BLACK:
        printw(" Winner is Black ");
        break;
      case CellColor::WHITE:
        printw(" Winner is White ");
        break;
      default:
        printw(" Draw ");
        break;
    }
    ::move(Board::END.y + 2, Board::END.x - 6);
    printw(" %02d %02d ", board_->black(), board_->white());
    log_records(*logs_, winner);
}

Point Reversi::move() const
{
    Point p;
    char c;

    if (board_->empty(p)){
        print_stone(p, now_);
    }
    else {
        print_coordinate(p);
    }

    c = getch();
    while (c != '\n' || not board_->can_put(p, now_)){
        if (board_->empty(p)){
            clear_stone(p);
        }
        else {
            clear_coordinate(p);
        }
        switch (c){
          case 'h':
            p.x = (p.x + Board::COL - 1) % Board::COL;
            break;
          case 'j':
            p.y = (p.y + 1) % Board::ROW;
            break;
          case 'k':
            p.y = (p.y + Board::ROW - 1) % Board::ROW;
            break;
          case 'l':
            p.x = (p.x + 1) % Board::COL;
            break;
          case ' ':
            return (Point(-1, -1));
        }
        if (board_->empty(p)){
            print_stone(p, now_);
        }
        else {
            print_coordinate(p);
        }
        c = getch();
    }
    clear_stone(p);

    return (p);
}

void Reversi::change()
{
    now_ = next_;
    next_.reverse();
}

} // namespace roadagain
<|endoftext|>


<commit_before>#include <stdbool.h>
#include <stdio.h>
#include "ds3.h"
#include "test.h"
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE( get_all_objects ) {
    uint64_t num_objs;
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, bucket_name);
    ds3_request_set_name(request, "%txt%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    handle_error(error);
    num_objs = response->num_objects;
    BOOST_CHECK_EQUAL(num_objs, 5);

    ds3_free_request(request);
    ds3_free_objects_response(response);

    clear_bucket(client, bucket_name);
    free_client(client);
}

BOOST_AUTO_TEST_CASE( get_no_objects ) {
    uint64_t num_objs;
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, bucket_name);
    ds3_request_set_name(request, "%frankenstein.txt%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    handle_error(error);
    num_objs = response->num_objects;
    BOOST_CHECK_EQUAL(num_objs, 0);

    ds3_free_request(request);
    ds3_free_objects_response(response);

    clear_bucket(client, bucket_name);
    free_client(client);
}

BOOST_AUTO_TEST_CASE( get_two_objects ) {
    uint64_t num_objs;
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, bucket_name);
    ds3_request_set_name(request, "%ulysses%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    handle_error(error);
    num_objs = response->num_objects;
    BOOST_CHECK_EQUAL(num_objs, 2);

    ds3_free_request(request);
    ds3_free_objects_response(response);

    clear_bucket(client, bucket_name);
    free_client(client);
}

BOOST_AUTO_TEST_CASE( get_one_objects ) {
    uint64_t num_objs;
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, bucket_name);
    ds3_request_set_name(request, "%ulysses.txt%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    handle_error(error);
    num_objs = response->num_objects;
    BOOST_CHECK_EQUAL(num_objs, 1);

    ds3_free_request(request);
    ds3_free_objects_response(response);

    clear_bucket(client, bucket_name);
    free_client(client);
}

BOOST_AUTO_TEST_CASE(get_one_objects_with_plus) {
	uint64_t num_objs;
	ds3_client* client = get_client();
	ds3_get_objects_response* response;
	const char* bucket_name = "Get_objects_with_plus";
	const char* plus_object = "Plus+Object"

	ds3_request* put_request = ds3_init_put_object_for_job(bucket_name, plus_object, 0, 1024, NULL);
	ds3_error* error = ds3_put_object(client, put_request, NULL, NULL);
	ds3_free_request(put_request);
	handle_error(error);

	ds3_request* request = ds3_init_get_objects();
	ds3_request_set_bucket_name(request, bucket_name);
	ds3_request_set_name(request, plus_object);
	error = ds3_get_objects(client, request, &response);

	handle_error(error);
	num_objs = response->num_objects;
	BOOST_CHECK_EQUAL(num_objs, 1);

	ds3_free_request(request);
	ds3_free_objects_response(response);

	clear_bucket(client, bucket_name);
	free_client(client);
}

BOOST_AUTO_TEST_CASE( get_folder_and_objects ) {
    uint64_t num_objs;
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, bucket_name);
    ds3_request_set_name(request, "%resources%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    handle_error(error);
    num_objs = response->num_objects;
    BOOST_CHECK_EQUAL(num_objs, 5);

    ds3_free_request(request);
    ds3_free_objects_response(response);

    clear_bucket(client, bucket_name);
    free_client(client);
}

BOOST_AUTO_TEST_CASE( get_incorrect_bucket_name ) {
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, "fake_bucket");
    ds3_request_set_name(request, "%resources%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    BOOST_CHECK(error!=NULL);
    BOOST_CHECK(error->error->status_code == 404);

    ds3_free_request(request);
    ds3_free_error(error);

    clear_bucket(client, bucket_name);
    free_client(client);
}
<commit_msg>Add special char and + tests to query param escaping<commit_after>#include <stdbool.h>
#include <stdio.h>
#include "ds3.h"
#include "test.h"
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE( get_all_objects ) {
    uint64_t num_objs;
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, bucket_name);
    ds3_request_set_name(request, "%txt%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    handle_error(error);
    num_objs = response->num_objects;
    BOOST_CHECK_EQUAL(num_objs, 5);

    ds3_free_request(request);
    ds3_free_objects_response(response);

    clear_bucket(client, bucket_name);
    free_client(client);
}

BOOST_AUTO_TEST_CASE( get_no_objects ) {
    uint64_t num_objs;
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, bucket_name);
    ds3_request_set_name(request, "%frankenstein.txt%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    handle_error(error);
    num_objs = response->num_objects;
    BOOST_CHECK_EQUAL(num_objs, 0);

    ds3_free_request(request);
    ds3_free_objects_response(response);

    clear_bucket(client, bucket_name);
    free_client(client);
}

BOOST_AUTO_TEST_CASE( get_two_objects ) {
    uint64_t num_objs;
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, bucket_name);
    ds3_request_set_name(request, "%ulysses%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    handle_error(error);
    num_objs = response->num_objects;
    BOOST_CHECK_EQUAL(num_objs, 2);

    ds3_free_request(request);
    ds3_free_objects_response(response);

    clear_bucket(client, bucket_name);
    free_client(client);
}

BOOST_AUTO_TEST_CASE( get_one_objects ) {
    uint64_t num_objs;
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, bucket_name);
    ds3_request_set_name(request, "%ulysses.txt%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    handle_error(error);
    num_objs = response->num_objects;
    BOOST_CHECK_EQUAL(num_objs, 1);

    ds3_free_request(request);
    ds3_free_objects_response(response);

    clear_bucket(client, bucket_name);
    free_client(client);
}

BOOST_AUTO_TEST_CASE(get_objects_with_plus_query_param) {

        printf("-----Testing Search Object with +-------\n");
	uint64_t num_objs;
	ds3_client* client = get_client();
	ds3_get_objects_response* response;
	const char* bucket_name = "get_objects_with_plus_query_param";
	const char* plus_object = "Plus+Object";

        ds3_request* put_bucket_request = ds3_init_put_bucket(bucket_name);
    	ds3_error* bucket_error = ds3_put_bucket(client, put_bucket_request);
    	ds3_free_request(put_bucket_request);

	handle_error(bucket_error);

	ds3_request* put_request = ds3_init_put_object_for_job(bucket_name, plus_object, 0, 1024, NULL);
        FILE* obj_file = fopen("resources/beowulf.txt", "r");

	ds3_error* error = ds3_put_object(client, put_request, obj_file, ds3_read_from_file);

	ds3_free_request(put_request);
	fclose(obj_file);

	handle_error(error);

	ds3_request* request = ds3_init_get_objects();
	ds3_request_set_bucket_name(request, bucket_name);
	ds3_request_set_name(request, plus_object);
	error = ds3_get_objects(client, request, &response);

	handle_error(error);
	num_objs = response->num_objects;
	BOOST_CHECK_EQUAL(num_objs, 1);

	ds3_free_request(request);
	ds3_free_objects_response(response);

	clear_bucket(client, bucket_name);
	free_client(client);
}

BOOST_AUTO_TEST_CASE(get_objects_with_special_chars_query_param) {

        printf("-----Testing Search Object with special char-------\n");
	uint64_t num_objs;
	ds3_client* client = get_client();
	ds3_get_objects_response* response;
	const char* bucket_name = "TestSpecialCharacterInObjectName";
	const char* special_char_object = "varsity1314/_projects/VARSITY 13-14/_versions/Varsity 13-14 (2015-10-05 1827)/_project/Trash/PCMAC HD.avb";

        ds3_request* put_bucket_request = ds3_init_put_bucket(bucket_name);
    	ds3_error* bucket_error = ds3_put_bucket(client, put_bucket_request);
    	ds3_free_request(put_bucket_request);

	handle_error(bucket_error);

	ds3_request* put_request = ds3_init_put_object_for_job(bucket_name, special_char_object, 0, 1024, NULL);
        FILE* obj_file = fopen("resources/beowulf.txt", "r");

	ds3_error* error = ds3_put_object(client, put_request, obj_file, ds3_read_from_file);

	ds3_free_request(put_request);
	fclose(obj_file);

	handle_error(error);

	ds3_request* request = ds3_init_get_objects();
	ds3_request_set_bucket_name(request, bucket_name);
	ds3_request_set_name(request, special_char_object);
	error = ds3_get_objects(client, request, &response);

	handle_error(error);
	num_objs = response->num_objects;
	BOOST_CHECK_EQUAL(num_objs, 1);

	ds3_free_request(request);
	ds3_free_objects_response(response);

	clear_bucket(client, bucket_name);
	free_client(client);
}

BOOST_AUTO_TEST_CASE( get_folder_and_objects ) {
    uint64_t num_objs;
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, bucket_name);
    ds3_request_set_name(request, "%resources%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    handle_error(error);
    num_objs = response->num_objects;
    BOOST_CHECK_EQUAL(num_objs, 5);

    ds3_free_request(request);
    ds3_free_objects_response(response);

    clear_bucket(client, bucket_name);
    free_client(client);
}

BOOST_AUTO_TEST_CASE( get_incorrect_bucket_name ) {
    ds3_client* client = get_client();
    ds3_get_objects_response* response;
    const char* bucket_name = "search_bucket_test";
    populate_with_objects(client, bucket_name);

    ds3_request* request = ds3_init_get_objects();
    ds3_request_set_bucket_name(request, "fake_bucket");
    ds3_request_set_name(request, "%resources%");
    ds3_error* error = ds3_get_objects(client, request, &response);

    BOOST_CHECK(error!=NULL);
    BOOST_CHECK(error->error->status_code == 404);

    ds3_free_request(request);
    ds3_free_error(error);

    clear_bucket(client, bucket_name);
    free_client(client);
}
<|endoftext|>


<commit_before>/* options.cpp - CS 472 Project #3: Genetic Programming
 * Copyright 2014 Andrew Schwartzmeyer
 *
 * Source file for options namespace
 */

#include <cassert>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>

#include <boost/program_options.hpp>

#include "options.hpp"

namespace options
{
  Position::Position(): x{0}, y{0}, direction{Direction::east} {}

  Map::Map(): width{0}, height{0}, ticks{0}, max_ticks{0}, score{0}, pieces{0},
	      position{Position{}} {}

  Map::Map(std::string filename, unsigned int ticks):
    width{0}, height{0}, ticks{0}, max_ticks{ticks}, score{0}, pieces{0},
    position{Position{}}
  {
    // Try to open the given file.
    std::ifstream data_file{filename};
    if (not data_file.is_open())
      {
	std::cerr << "File " << filename << " could not be read!\n";
	std::exit(EXIT_FAILURE);
      }

    // Parse file into map structure
    std::string line;
    while (data_file >> line)
      {
	std::vector<Cell> row;
	if (width != 0) row.reserve(width);
	for (const char& c : line)
	  {
	    if (c != '.' and c != 'x')
	      {
		std::cerr << "File " << filename << " had bad cells!\n"
			  << "They were: " << c << std::endl;
		std::exit(EXIT_FAILURE);
	      }
	    else
	      {
		Cell cell = (c == 'x') ? Cell{Cell::food} : Cell{Cell::blank};
		row.emplace_back(cell);
		if (cell == Cell::food) ++pieces;
	      }
	  }
	if (width == 0) width = row.size(); // Get initial width
	// Verify all lines are same width
	else if (row.size() != width)
	  {
	    std::cerr << "File " << filename << " had uneven lines!\n"
		      << "The width is: " << width
		      << " and the line was " << row.size() << std::endl;
	    std::exit(EXIT_FAILURE);
	  }
	rows.emplace_back(row);
      }
    height = rows.size();
  }

  bool
  Map::active() const
  {
    return ticks < max_ticks;
  }

  bool
  Map::look() const
  {
    Position ahead = position;
    switch (position.direction)
      {
      case Direction::north:
	ahead.y = (position.y - 1) % height; break;
      case Direction::west:
	ahead.x = (position.x - 1) % width; break;
      case Direction::south:
	ahead.y = (position.y + 1) % height; break;
      case Direction::east:
	ahead.y = (position.x + 1) % width; break;
      }
    return rows[ahead.y][ahead.x] == Cell::food;
  }

  void
  Map::forward()
  {
    switch (position.direction)
      {
      case Direction::north:
	position.y = (position.y - 1) % height; break;
      case Direction::west:
	position.x = (position.x - 1) % width; break;
      case Direction::south:
	position.y = (position.y + 1) % height; break;
      case Direction::east:
	position.y = (position.x + 1) % width; break;
      }
    // Increment score if moved onto food
    if (rows[position.y][position.x] == Cell::food) ++score;

    // Mark location on map as visitied
    rows[position.y][position.x] = Cell::marked;

    ++ticks;
  }

  void
  Map::left()
  {
    switch (position.direction)
      {
      case Direction::north:
	position.direction = Direction::west; break;
      case Direction::west:
	position.direction = Direction::south; break;
      case Direction::south:
	position.direction = Direction::east; break;
      case Direction::east:
	position.direction = Direction::north; break;
      }
    ++ticks;
  }

  void
  Map::right()
  {
    switch (position.direction)
      {
      case Direction::north:
	position.direction = Direction::east; break;
      case Direction::east:
	position.direction = Direction::south; break;
      case Direction::south:
	position.direction = Direction::west; break;
      case Direction::west:
	position.direction = Direction::north; break;
      }
    ++ticks;
  }

  unsigned int
  Map::fitness() const
  {
    return score;
  }

  unsigned int
  Map::max() const
  {
    return pieces;
  }

  std::string Map::print() const
  {
    std::stringstream out;
    out << "# 'x' is food and 'o' is ant trail\n";
    for (const std::vector<Cell>& row : rows)
      {
	for (const Cell& cell : row)
	  {
	    // Add blank, food, and marked locations
	    switch (cell)
	      {
	      case Cell::blank: out << '.'; break;
	      case Cell::food: out << 'x'; break;
	      case Cell::marked: out << 'o'; break;
	      }
	  }
	// Add newline after each row
	out << '\n';
      }
    return out.str();
  }

  // Validates options parameters; should instead be unit tests.
  void
  Options::validate() const
  {
    assert(trials > 0);
    assert(generations > 0);
    assert(pop_size > 0);
    assert(tourney_size > 0 and tourney_size <= pop_size);
    assert(fitter_size > 0 and fitter_size <= pop_size);
    assert(crossover_size == 2 or crossover_size == 0);
    assert(elitism_size <= pop_size);
    assert(penalty >= 0 and penalty <= 1);
    assert(grow_chance >= 0 and grow_chance <= 1);
    assert(over_select_chance >= 0 and over_select_chance <= 1);
    assert(mutate_chance >= 0 and mutate_chance <= 1);
    assert(crossover_chance >= 0 and crossover_chance <= 1);
    assert(internals_chance >= 0 and internals_chance <= 1);
  }

  /* Given main's argc and argv, this will parse command-line options
     and the optional config file to return a built-up Options struct
     with all values, default or explicitly set. */
  const Options
  parse(int argc, char* argv[])
  {
    using std::string;
    using namespace boost::program_options;

    string filename;
    unsigned int ticks;
    Options options;

    positional_options_description positionals;
    variables_map variables_map;
    options_description description{"Allowed options"};

    // sets up all available CLI options
    description.add_options()
      ("help,h", "produce help message")

      ("config,c", value<string>()->
       default_value("search.cfg"),
       "specify the configuration file")

      ("file,f", value<string>(&filename)->
       default_value("test/santa-fe-trail.dat"),
       "specify the location of the columnized test data \"X Y\"")

      ("trials,t", value<unsigned int>(&options.trials)->
       default_value(4),
       "set the number of trials to run")

      ("generations,g",
       value<unsigned int>(&options.generations)->
       default_value(128),
       "set the number of iterations for which to run each trial")

      ("population,p",
       value<unsigned int>(&options.pop_size)->
       default_value(1024),
       "set the size of each population")

      ("min-depth", value<unsigned int>(&options.min_depth)->
       default_value(2),
       "set the minimum depth for initial populations")

      ("max-depth,d", value<unsigned int>(&options.max_depth)->
       default_value(6),
       "set the maximum depth for initial populations")

      ("depth-limit,l", value<unsigned int>(&options.depth_limit)->
       default_value(14),
       "set the depth limit for individuals")

      ("tournament-size,T",
       value<unsigned int>(&options.tourney_size)->
       default_value(3),
       "set the tournment size to adjust selection pressure")

      ("fitter-size,F",
       value<unsigned int>(&options.fitter_size)->
       default_value(320),
       "set the population size of fitter group")

      ("crossover-size",
       value<unsigned int>(&options.crossover_size)->
       default_value(2),
       "set the crossover size(binary in current implementation)")

      ("elitism-size,E", value<unsigned int>(&options.elitism_size)->
       default_value(3),
       "set the number of elitism replacements to make each iteration")

      ("ticks", value<unsigned int>(&ticks)->
       default_value(600),
       "set the number of moves the ant may move")

      ("penalty,P", value<float>(&options.penalty)->
       default_value(0),
       "set the constant scalar of the size penalty for fitness")

      ("grow-chance", value<float>(&options.grow_chance)->
       default_value(0.5),
       "set the probability that an initial tree will be made by the grow method")

      ("over-select-chance,O", value<float>(&options.over_select_chance)->
       default_value(0.8),
       "set the probability that a selection is made from the fitter group")

      ("mutate-chance,M", value<float>(&options.mutate_chance)->
       default_value(0.05),
       "set the probability that a single node will mutate")

      ("crossover-chance,C", value<float>(&options.crossover_chance)->
       default_value(0.8),
       "set the probability that crossover will be performed")

      ("internals-chance", value<float>(&options.internals_chance)->
       default_value(0.9),
       "set the probability that a crossover target node will be an internal node")

      ("logs", value<string>(&options.logs_dir)->
       default_value("logs/"),
       "set the save directory for log files")

      ("plots", value<string>(&options.plots_dir)->
       default_value("plots/"),
       "set the save directory for plot data files")

      ("verbosity,v", value<unsigned int>(&options.verbosity)->
       default_value(1),
       "set the verbosity: 0 - no logging; 1 - normal logging; 2 - debug output");

    /* Stores CLI and config file options. Will catch exception and
       exit with EXIT_FAILURE if given bad input. */
    try
      {
	store(parse_command_line(argc, argv, description), variables_map);

	std::ifstream config{variables_map["config"].as<string>()};
	if (config.is_open())
	  store(parse_config_file(config, description), variables_map);

	notify(variables_map);
      }
    catch (std::exception& e)
      {
	std::cerr << e.what() << std::endl;
	std::exit(EXIT_FAILURE);
      }

    // Print options help and exit with EXIT_SUCCESS when finished.
    if (variables_map.count("help"))
      {
	std::cout << "Genetic Program implemented in C++ by Andrew Schwartzmeyer\n"
		  << "Code located at https://github.com/andschwa/uidaho-cs472-project3\n\n"
		  << "Logs saved to <" << options.logs_dir << ">/<Unix time>.dat\n"
		  << "Ant maps saved to <" << options.plots_dir << ">/<Unix time>.dat\n"
		  << "GNUPlot PNG generation scripts in <tools>'\n\n"
		  << description << std::endl;
	std::exit(EXIT_SUCCESS);
      }

    // get values from given test file
    options.map = Map(filename, ticks);
    options.validate();

    return options;
  }
}
<commit_msg>Fixing crossover-size option help<commit_after>/* options.cpp - CS 472 Project #3: Genetic Programming
 * Copyright 2014 Andrew Schwartzmeyer
 *
 * Source file for options namespace
 */

#include <cassert>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>

#include <boost/program_options.hpp>

#include "options.hpp"

namespace options
{
  Position::Position(): x{0}, y{0}, direction{Direction::east} {}

  Map::Map(): width{0}, height{0}, ticks{0}, max_ticks{0}, score{0}, pieces{0},
	      position{Position{}} {}

  Map::Map(std::string filename, unsigned int ticks):
    width{0}, height{0}, ticks{0}, max_ticks{ticks}, score{0}, pieces{0},
    position{Position{}}
  {
    // Try to open the given file.
    std::ifstream data_file{filename};
    if (not data_file.is_open())
      {
	std::cerr << "File " << filename << " could not be read!\n";
	std::exit(EXIT_FAILURE);
      }

    // Parse file into map structure
    std::string line;
    while (data_file >> line)
      {
	std::vector<Cell> row;
	if (width != 0) row.reserve(width);
	for (const char& c : line)
	  {
	    if (c != '.' and c != 'x')
	      {
		std::cerr << "File " << filename << " had bad cells!\n"
			  << "They were: " << c << std::endl;
		std::exit(EXIT_FAILURE);
	      }
	    else
	      {
		Cell cell = (c == 'x') ? Cell{Cell::food} : Cell{Cell::blank};
		row.emplace_back(cell);
		if (cell == Cell::food) ++pieces;
	      }
	  }
	if (width == 0) width = row.size(); // Get initial width
	// Verify all lines are same width
	else if (row.size() != width)
	  {
	    std::cerr << "File " << filename << " had uneven lines!\n"
		      << "The width is: " << width
		      << " and the line was " << row.size() << std::endl;
	    std::exit(EXIT_FAILURE);
	  }
	rows.emplace_back(row);
      }
    height = rows.size();
  }

  bool
  Map::active() const
  {
    return ticks < max_ticks;
  }

  bool
  Map::look() const
  {
    Position ahead = position;
    switch (position.direction)
      {
      case Direction::north:
	ahead.y = (position.y - 1) % height; break;
      case Direction::west:
	ahead.x = (position.x - 1) % width; break;
      case Direction::south:
	ahead.y = (position.y + 1) % height; break;
      case Direction::east:
	ahead.y = (position.x + 1) % width; break;
      }
    return rows[ahead.y][ahead.x] == Cell::food;
  }

  void
  Map::forward()
  {
    switch (position.direction)
      {
      case Direction::north:
	position.y = (position.y - 1) % height; break;
      case Direction::west:
	position.x = (position.x - 1) % width; break;
      case Direction::south:
	position.y = (position.y + 1) % height; break;
      case Direction::east:
	position.y = (position.x + 1) % width; break;
      }
    // Increment score if moved onto food
    if (rows[position.y][position.x] == Cell::food) ++score;

    // Mark location on map as visitied
    rows[position.y][position.x] = Cell::marked;

    ++ticks;
  }

  void
  Map::left()
  {
    switch (position.direction)
      {
      case Direction::north:
	position.direction = Direction::west; break;
      case Direction::west:
	position.direction = Direction::south; break;
      case Direction::south:
	position.direction = Direction::east; break;
      case Direction::east:
	position.direction = Direction::north; break;
      }
    ++ticks;
  }

  void
  Map::right()
  {
    switch (position.direction)
      {
      case Direction::north:
	position.direction = Direction::east; break;
      case Direction::east:
	position.direction = Direction::south; break;
      case Direction::south:
	position.direction = Direction::west; break;
      case Direction::west:
	position.direction = Direction::north; break;
      }
    ++ticks;
  }

  unsigned int
  Map::fitness() const
  {
    return score;
  }

  unsigned int
  Map::max() const
  {
    return pieces;
  }

  std::string Map::print() const
  {
    std::stringstream out;
    out << "# 'x' is food and 'o' is ant trail\n";
    for (const std::vector<Cell>& row : rows)
      {
	for (const Cell& cell : row)
	  {
	    // Add blank, food, and marked locations
	    switch (cell)
	      {
	      case Cell::blank: out << '.'; break;
	      case Cell::food: out << 'x'; break;
	      case Cell::marked: out << 'o'; break;
	      }
	  }
	// Add newline after each row
	out << '\n';
      }
    return out.str();
  }

  // Validates options parameters; should instead be unit tests.
  void
  Options::validate() const
  {
    assert(trials > 0);
    assert(generations > 0);
    assert(pop_size > 0);
    assert(tourney_size > 0 and tourney_size <= pop_size);
    assert(fitter_size > 0 and fitter_size <= pop_size);
    assert(crossover_size == 2 or crossover_size == 0);
    assert(elitism_size <= pop_size);
    assert(penalty >= 0 and penalty <= 1);
    assert(grow_chance >= 0 and grow_chance <= 1);
    assert(over_select_chance >= 0 and over_select_chance <= 1);
    assert(mutate_chance >= 0 and mutate_chance <= 1);
    assert(crossover_chance >= 0 and crossover_chance <= 1);
    assert(internals_chance >= 0 and internals_chance <= 1);
  }

  /* Given main's argc and argv, this will parse command-line options
     and the optional config file to return a built-up Options struct
     with all values, default or explicitly set. */
  const Options
  parse(int argc, char* argv[])
  {
    using std::string;
    using namespace boost::program_options;

    string filename;
    unsigned int ticks;
    Options options;

    positional_options_description positionals;
    variables_map variables_map;
    options_description description{"Allowed options"};

    // sets up all available CLI options
    description.add_options()
      ("help,h", "produce help message")

      ("config,c", value<string>()->
       default_value("search.cfg"),
       "specify the configuration file")

      ("file,f", value<string>(&filename)->
       default_value("test/santa-fe-trail.dat"),
       "specify the location of the columnized test data \"X Y\"")

      ("trials,t", value<unsigned int>(&options.trials)->
       default_value(4),
       "set the number of trials to run")

      ("generations,g",
       value<unsigned int>(&options.generations)->
       default_value(128),
       "set the number of iterations for which to run each trial")

      ("population,p",
       value<unsigned int>(&options.pop_size)->
       default_value(1024),
       "set the size of each population")

      ("min-depth", value<unsigned int>(&options.min_depth)->
       default_value(2),
       "set the minimum depth for initial populations")

      ("max-depth,d", value<unsigned int>(&options.max_depth)->
       default_value(6),
       "set the maximum depth for initial populations")

      ("depth-limit,l", value<unsigned int>(&options.depth_limit)->
       default_value(14),
       "set the depth limit for individuals")

      ("tournament-size,T",
       value<unsigned int>(&options.tourney_size)->
       default_value(3),
       "set the tournment size to adjust selection pressure")

      ("fitter-size,F",
       value<unsigned int>(&options.fitter_size)->
       default_value(320),
       "set the population size of fitter group")

      ("crossover-size",
       value<unsigned int>(&options.crossover_size)->
       default_value(2),
       "set the crossover size (2 for binary; 0 to disable)")

      ("elitism-size,E", value<unsigned int>(&options.elitism_size)->
       default_value(3),
       "set the number of elitism replacements to make each iteration")

      ("ticks", value<unsigned int>(&ticks)->
       default_value(600),
       "set the number of moves the ant may move")

      ("penalty,P", value<float>(&options.penalty)->
       default_value(0),
       "set the constant scalar of the size penalty for fitness")

      ("grow-chance", value<float>(&options.grow_chance)->
       default_value(0.5),
       "set the probability that an initial tree will be made by the grow method")

      ("over-select-chance,O", value<float>(&options.over_select_chance)->
       default_value(0.8),
       "set the probability that a selection is made from the fitter group")

      ("mutate-chance,M", value<float>(&options.mutate_chance)->
       default_value(0.05),
       "set the probability that a single node will mutate")

      ("crossover-chance,C", value<float>(&options.crossover_chance)->
       default_value(0.8),
       "set the probability that crossover will be performed")

      ("internals-chance", value<float>(&options.internals_chance)->
       default_value(0.9),
       "set the probability that a crossover target node will be an internal node")

      ("logs", value<string>(&options.logs_dir)->
       default_value("logs/"),
       "set the save directory for log files")

      ("plots", value<string>(&options.plots_dir)->
       default_value("plots/"),
       "set the save directory for plot data files")

      ("verbosity,v", value<unsigned int>(&options.verbosity)->
       default_value(1),
       "set the verbosity: 0 - no logging; 1 - normal logging; 2 - debug output");

    /* Stores CLI and config file options. Will catch exception and
       exit with EXIT_FAILURE if given bad input. */
    try
      {
	store(parse_command_line(argc, argv, description), variables_map);

	std::ifstream config{variables_map["config"].as<string>()};
	if (config.is_open())
	  store(parse_config_file(config, description), variables_map);

	notify(variables_map);
      }
    catch (std::exception& e)
      {
	std::cerr << e.what() << std::endl;
	std::exit(EXIT_FAILURE);
      }

    // Print options help and exit with EXIT_SUCCESS when finished.
    if (variables_map.count("help"))
      {
	std::cout << "Genetic Program implemented in C++ by Andrew Schwartzmeyer\n"
		  << "Code located at https://github.com/andschwa/uidaho-cs472-project3\n\n"
		  << "Logs saved to <" << options.logs_dir << ">/<Unix time>.dat\n"
		  << "Ant maps saved to <" << options.plots_dir << ">/<Unix time>.dat\n"
		  << "GNUPlot PNG generation scripts in <tools>'\n\n"
		  << description << std::endl;
	std::exit(EXIT_SUCCESS);
      }

    // get values from given test file
    options.map = Map(filename, ticks);
    options.validate();

    return options;
  }
}
<|endoftext|>


<commit_before>// cfiles, an analysis frontend for the Chemfiles library
// Copyright (C) 2015-2016 Guillaume Fraux
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

#include <docopt/docopt.h>
#include <algorithm>
#include <fstream>

#include "Angles.hpp"
#include "Errors.hpp"
#include "geometry.hpp"

using namespace chemfiles;

static const double pi = 3.141592653589793238463;
static const std::string OPTIONS =
R"(Compute distribution of angles or dihedral angles along a trajectory. The
angle can be specified using the chemfiles selection language. It is possible
to provide an alternative unit cell or topology for the trajectory file if they
are not defined in the trajectory format.

For more information about chemfiles selection language, please see
http://chemfiles.github.io/chemfiles/latest/selections.html

Usage:
  cfiles angles [options] <trajectory>
  cfiles angles (-h | --help)

Examples:
  cfiles angles water.tng -s "angles: name(#1) H and name(#2) O and name(#3) H"
  cfiles angles butane.tng -s "dihedrals: name(#2) C and name(#3) C"
  cfiles angles methane.xyz --cell 15:15:25 --guess-bonds --points=150
  cfiles angles result.xtc --topology=initial.mol --topology-format=PDB
  cfiles angles simulation.pdb --steps=:1000:5 -o partial-angles.dat

Options:
  -h --help                     show this help
  -o <file>, --output=<file>    write result to <file>. This default to the
                                trajectory file name with the `.ang` extension.
  -s <sel>, --selection=<sel>   selection to use for the atoms. This must be a
                                selection of size 3 (for angles) or 4 (for
                                dihedral angles) [default: angles: all]
  -p <n>, --points=<n>          number of points in the histogram [default: 200])";

std::string AngleDistribution::description() const {
    return "compute angles and dihedral angles distribution";
}

Averager<double> AngleDistribution::setup(int argc, const char* argv[]) {
    auto options = command_header("angles", AngleDistribution().description());
    options += "Guillaume Fraux <guillaume@fraux.fr>\n\n";
    options += std::string(OPTIONS) + AveCommand::AVERAGE_OPTIONS;
    auto args = docopt::docopt(options, {argv, argv + argc}, true, "");

    AveCommand::parse_options(args);

    if (args["--output"]){
        options_.outfile = args["--output"].asString();
    } else {
        options_.outfile = AveCommand::options().trajectory + ".ang";
    }

    options_.npoints = stol(args["--points"].asString());
    options_.selection = args["--selection"].asString();

    selection_ = Selection(options_.selection);
    if (selection_.size() == 3) {
        return Averager<double>(options_.npoints, 0, pi);
    } else if (selection_.size() == 4) {
        return Averager<double>(options_.npoints, 0, 2*pi);
    } else {
        throw CFilesError("Can not use a selection with less than three atoms in angle distribution.");
    }
}

void AngleDistribution::finish(const Histogram<double>& histogram) {
    auto max = *std::max_element(histogram.begin(), histogram.end());

    std::ofstream outfile(options_.outfile, std::ios::out);
    if(outfile.is_open()) {
        outfile << "# Angles distribution in trajectory " << AveCommand::options().trajectory << std::endl;
        outfile << "# Selection: " << options_.selection << std::endl;

        double dr = histogram.bin_size();
        for (size_t i=0; i<histogram.size(); i++){
            outfile << i*180/pi * dr << "  " << histogram[i] / max << "\n";
        }
    } else {
        throw CFilesError("Could not open the '" + options_.outfile + "' file.");
    }
}

void AngleDistribution::accumulate(const Frame& frame, Histogram<double>& histogram) {
    auto positions = frame.positions();
    auto cell = frame.cell();

    auto matched = selection_.evaluate(frame);
    for (auto match: matched) {
        assert(match.size() == 3 || match.size() == 4);

        if (match.size() == 3) {
            auto i = match[0];
            auto j = match[1];
            auto k = match[2];
            auto r21 = cell.wrap(positions[i] - positions[j]);
            auto r23 = cell.wrap(positions[k] - positions[j]);
            auto theta = angle(r21, r23);
            histogram.insert(theta);
        } else if (match.size() == 4) {
            auto i = match[0];
            auto j = match[1];
            auto k = match[2];
            auto m = match[3];
            auto r12 = cell.wrap(positions[j] - positions[i]);
            auto r23 = cell.wrap(positions[k] - positions[j]);
            auto r34 = cell.wrap(positions[m] - positions[k]);
            auto phi = dihedral(r12, r23, r34);
            histogram.insert(phi);
        }
    }
}
<commit_msg>Throw an error when no angles match the selection (#17)<commit_after>// cfiles, an analysis frontend for the Chemfiles library
// Copyright (C) 2015-2016 Guillaume Fraux
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/

#include <docopt/docopt.h>
#include <algorithm>
#include <fstream>

#include "Angles.hpp"
#include "Errors.hpp"
#include "geometry.hpp"

using namespace chemfiles;

static const double pi = 3.141592653589793238463;
static const std::string OPTIONS =
R"(Compute distribution of angles or dihedral angles along a trajectory. The
angle can be specified using the chemfiles selection language. It is possible
to provide an alternative unit cell or topology for the trajectory file if they
are not defined in the trajectory format.

For more information about chemfiles selection language, please see
http://chemfiles.github.io/chemfiles/latest/selections.html

Usage:
  cfiles angles [options] <trajectory>
  cfiles angles (-h | --help)

Examples:
  cfiles angles water.tng -s "angles: name(#1) H and name(#2) O and name(#3) H"
  cfiles angles butane.tng -s "dihedrals: name(#2) C and name(#3) C"
  cfiles angles methane.xyz --cell 15:15:25 --guess-bonds --points=150
  cfiles angles result.xtc --topology=initial.mol --topology-format=PDB
  cfiles angles simulation.pdb --steps=:1000:5 -o partial-angles.dat

Options:
  -h --help                     show this help
  -o <file>, --output=<file>    write result to <file>. This default to the
                                trajectory file name with the `.ang` extension.
  -s <sel>, --selection=<sel>   selection to use for the atoms. This must be a
                                selection of size 3 (for angles) or 4 (for
                                dihedral angles) [default: angles: all]
  -p <n>, --points=<n>          number of points in the histogram [default: 200])";

std::string AngleDistribution::description() const {
    return "compute angles and dihedral angles distribution";
}

Averager<double> AngleDistribution::setup(int argc, const char* argv[]) {
    auto options = command_header("angles", AngleDistribution().description());
    options += "Guillaume Fraux <guillaume@fraux.fr>\n\n";
    options += std::string(OPTIONS) + AveCommand::AVERAGE_OPTIONS;
    auto args = docopt::docopt(options, {argv, argv + argc}, true, "");

    AveCommand::parse_options(args);

    if (args["--output"]){
        options_.outfile = args["--output"].asString();
    } else {
        options_.outfile = AveCommand::options().trajectory + ".ang";
    }

    options_.npoints = stol(args["--points"].asString());
    options_.selection = args["--selection"].asString();

    selection_ = Selection(options_.selection);
    if (selection_.size() == 3) {
        return Averager<double>(options_.npoints, 0, pi);
    } else if (selection_.size() == 4) {
        return Averager<double>(options_.npoints, 0, 2*pi);
    } else {
        throw CFilesError("Can not use a selection with less than three atoms in angle distribution.");
    }
}

void AngleDistribution::finish(const Histogram<double>& histogram) {
    auto max = *std::max_element(histogram.begin(), histogram.end());

    if (max == 0) {
        throw CFilesError("No angle corresponding to the '" + selection_.string() + "' selection found.");
    }

    std::ofstream outfile(options_.outfile, std::ios::out);
    if(outfile.is_open()) {
        outfile << "# Angles distribution in trajectory " << AveCommand::options().trajectory << std::endl;
        outfile << "# Selection: " << options_.selection << std::endl;

        double dr = histogram.bin_size();
        for (size_t i=0; i<histogram.size(); i++){
            outfile << i*180/pi * dr << "  " << histogram[i] / max << "\n";
        }
    } else {
        throw CFilesError("Could not open the '" + options_.outfile + "' file.");
    }
}

void AngleDistribution::accumulate(const Frame& frame, Histogram<double>& histogram) {
    auto positions = frame.positions();
    auto cell = frame.cell();

    auto matched = selection_.evaluate(frame);
    for (auto match: matched) {
        assert(match.size() == 3 || match.size() == 4);

        if (match.size() == 3) {
            auto i = match[0];
            auto j = match[1];
            auto k = match[2];
            auto r21 = cell.wrap(positions[i] - positions[j]);
            auto r23 = cell.wrap(positions[k] - positions[j]);
            auto theta = angle(r21, r23);
            histogram.insert(theta);
        } else if (match.size() == 4) {
            auto i = match[0];
            auto j = match[1];
            auto k = match[2];
            auto m = match[3];
            auto r12 = cell.wrap(positions[j] - positions[i]);
            auto r23 = cell.wrap(positions[k] - positions[j]);
            auto r34 = cell.wrap(positions[m] - positions[k]);
            auto phi = dihedral(r12, r23, r34);
            histogram.insert(phi);
        }
    }
}
<|endoftext|>


<commit_before>#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>

using namespace cv;
using namespace std;

void help(char** argv)
{
	cout << "\nDemonstrate mean shift based color segmentation in spatial pyramid.\n"
    << "Call:\n   " << argv[0] << " image\n"
    << "This program allows you to set the spatial and color radius\n"
    << "of the mean shift window as well as the number of pyramid reduction levels explored\n"
    << endl;
}

//This colors the segmentations
void floodFillPostprocess( Mat& img, const Scalar& colorDiff=Scalar::all(1) )
{
    CV_Assert( !img.empty() );
    RNG rng = theRNG();
    Mat mask( img.rows+2, img.cols+2, CV_8UC1, Scalar::all(0) );
    for( int y = 0; y < img.rows; y++ )
    {
        for( int x = 0; x < img.cols; x++ )
        {
            if( mask.at<uchar>(y+1, x+1) == 0 )
            {
                Scalar newVal( rng(256), rng(256), rng(256) );
                floodFill( img, mask, Point(x,y), newVal, 0, colorDiff, colorDiff );
            }
        }
    }
}

string winName = "meanshift";
int spatialRad, colorRad, maxPyrLevel;
Mat img, res;

void meanShiftSegmentation( int, void* )
{
    cout << "spatialRad=" << spatialRad << "; "
         << "colorRad=" << colorRad << "; "
         << "maxPyrLevel=" << maxPyrLevel << endl;
    pyrMeanShiftFiltering( img, res, spatialRad, colorRad, maxPyrLevel );
    floodFillPostprocess( res, Scalar::all(2) );
    imshow( winName, res );
}

int main(int argc, char** argv)
{
    if( argc !=2 )
    {
    	help(argv);
        return -1;
    }

    img = imread( argv[1] );
    if( img.empty() )
        return -1;

    spatialRad = 10;
    colorRad = 10;
    maxPyrLevel = 1;

    namedWindow( winName, CV_WINDOW_AUTOSIZE );

    createTrackbar( "spatialRad", winName, &spatialRad, 80, meanShiftSegmentation );
    createTrackbar( "colorRad", winName, &colorRad, 60, meanShiftSegmentation );
    createTrackbar( "maxPyrLevel", winName, &maxPyrLevel, 5, meanShiftSegmentation );

    meanShiftSegmentation(0, 0);
    waitKey();
    return 0;
}
<commit_msg>revamped<commit_after>#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>

using namespace cv;
using namespace std;

void help(char** argv)
{
	cout << "\nDemonstrate mean-shift based color segmentation in spatial pyramid.\n"
    << "Call:\n   " << argv[0] << " image\n"
    << "This program allows you to set the spatial and color radius\n"
    << "of the mean shift window as well as the number of pyramid reduction levels explored\n"
    << endl;
}

//This colors the segmentations
void floodFillPostprocess( Mat& img, const Scalar& colorDiff=Scalar::all(1) )
{
    CV_Assert( !img.empty() );
    RNG rng = theRNG();
    Mat mask( img.rows+2, img.cols+2, CV_8UC1, Scalar::all(0) );
    for( int y = 0; y < img.rows; y++ )
    {
        for( int x = 0; x < img.cols; x++ )
        {
            if( mask.at<uchar>(y+1, x+1) == 0 )
            {
                Scalar newVal( rng(256), rng(256), rng(256) );
                floodFill( img, mask, Point(x,y), newVal, 0, colorDiff, colorDiff );
            }
        }
    }
}

string winName = "meanshift";
int spatialRad, colorRad, maxPyrLevel;
Mat img, res;

void meanShiftSegmentation( int, void* )
{
    cout << "spatialRad=" << spatialRad << "; "
         << "colorRad=" << colorRad << "; "
         << "maxPyrLevel=" << maxPyrLevel << endl;
    pyrMeanShiftFiltering( img, res, spatialRad, colorRad, maxPyrLevel );
    floodFillPostprocess( res, Scalar::all(2) );
    imshow( winName, res );
}

int main(int argc, char** argv)
{
    if( argc !=2 )
    {
    	help(argv);
        return -1;
    }

    img = imread( argv[1] );
    if( img.empty() )
        return -1;

    spatialRad = 10;
    colorRad = 10;
    maxPyrLevel = 1;

    namedWindow( winName, CV_WINDOW_AUTOSIZE );

    createTrackbar( "spatialRad", winName, &spatialRad, 80, meanShiftSegmentation );
    createTrackbar( "colorRad", winName, &colorRad, 60, meanShiftSegmentation );
    createTrackbar( "maxPyrLevel", winName, &maxPyrLevel, 5, meanShiftSegmentation );

    meanShiftSegmentation(0, 0);
    waitKey();
    return 0;
}
<|endoftext|>


<commit_before>/*
    __ _____ _____ _____
 __|  |   __|     |   | |  JSON for Modern C++ (test suite)
|  |  |__   |  |  | | | |  version 2.0.7
|_____|_____|_____|_|___|  https://github.com/nlohmann/json

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.

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

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

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

#include <array>
#include <string>
#include <memory>
#include "catch.hpp"

#include "json.hpp"

namespace udt
{
  struct age
  {
    int m_val;
  };

  struct name
  {
    std::string m_val;
  };

  struct address
  {
    std::string m_val;
  };

  struct person
  {
    age m_age;
    name m_name;
  };

  struct contact
  {
    person m_person;
    address m_address;
  };

  struct contact_book
  {
    name m_book_name;
    std::vector<contact> m_contacts;
  };
}

// to_json methods for default basic_json
namespace udt
{
  void to_json(nlohmann::json& j, age a)
  {
    j = a.m_val;
  }

  void to_json(nlohmann::json& j, name const& n)
  {
    j = n.m_val;
  }

  void to_json(nlohmann::json& j, person const& p)
  {
    using nlohmann::json;
    j = json{{"age", p.m_age}, {"name", p.m_name}};
  }

  void to_json(nlohmann::json& j, address const& a)
  {
    j = a.m_val;
  }

  void to_json(nlohmann::json& j, contact const& c)
  {
    using nlohmann::json;
    j = json{{"person", c.m_person}, {"address", c.m_address}};
  }

  void to_json(nlohmann::json& j, contact_book const& cb)
  {
    using nlohmann::json;
    j = json{{"name", cb.m_book_name}, {"contacts", cb.m_contacts}};
  }

  // operators
  bool operator==(age lhs, age rhs)
  {
    return lhs.m_val == rhs.m_val;
  }

  bool operator==(address const &lhs, address const &rhs)
  {
    return lhs.m_val == rhs.m_val;
  }

  bool operator==(name const &lhs, name const &rhs)
  {
    return lhs.m_val == rhs.m_val;
  }

  bool operator==(person const &lhs, person const &rhs)
  {
    return std::tie(lhs.m_name, lhs.m_age) == std::tie(rhs.m_name, rhs.m_age);
  }

  bool operator==(contact const &lhs, contact const &rhs)
  {
    return std::tie(lhs.m_person, lhs.m_address) ==
           std::tie(rhs.m_person, rhs.m_address);
  }

  bool operator==(contact_book const &lhs, contact_book const &rhs)
  {
    return std::tie(lhs.m_book_name, lhs.m_contacts) ==
           std::tie(rhs.m_book_name, rhs.m_contacts);
  }
}

// from_json methods for default basic_json
namespace udt
{
  void from_json(nlohmann::json const& j, age &a)
  {
    a.m_val = j.get<int>();
  }

  void from_json(nlohmann::json const& j, name &n)
  {
    n.m_val = j.get<std::string>();
  }

  void from_json(nlohmann::json const& j, person &p)
  {
    p.m_age = j["age"].get<age>();
    p.m_name = j["name"].get<name>();
  }

  void from_json(nlohmann::json const &j, address &a)
  {
    a.m_val = j.get<std::string>();
  }

  void from_json(nlohmann::json const& j, contact &c)
  {
    c.m_person = j["person"].get<person>();
    c.m_address = j["address"].get<address>();
  }

  void from_json(nlohmann::json const&j, contact_book &cb)
  {
    cb.m_book_name = j["name"].get<name>();
    cb.m_contacts = j["contacts"].get<std::vector<contact>>();
  }
}

TEST_CASE("basic usage", "[udt]")
{
  using nlohmann::json;

  // a bit narcissic maybe :) ?
  const udt::age a{23};
  const udt::name n{"theo"};
  const udt::person sfinae_addict{a, n};
  const udt::address addr{"Paris"};
  const udt::contact cpp_programmer{sfinae_addict, addr};
  const udt::contact_book book{{"C++"}, {cpp_programmer, cpp_programmer}};

  SECTION("conversion to json via free-functions")
  {
    CHECK(json(a) == json(23));
    CHECK(json(n) == json("theo"));
    CHECK(json(sfinae_addict) == R"({"name":"theo", "age":23})"_json);
    CHECK(json("Paris") == json(addr));
    CHECK(json(cpp_programmer) ==
          R"({"person" : {"age":23, "name":"theo"}, "address":"Paris"})"_json);

    CHECK(
        json(book) ==
        R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo"}, "address":"Paris"}, {"person" : {"age":23, "name":"theo"}, "address":"Paris"}]})"_json);
  }

  SECTION("conversion from json via free-functions")
  {
    const auto big_json =
        R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo"}, "address":"Paris"}, {"person" : {"age":23, "name":"theo"}, "address":"Paris"}]})"_json;
    const auto parsed_book = big_json.get<udt::contact_book>();
    const auto book_name = big_json["name"].get<udt::name>();
    const auto contacts = big_json["contacts"].get<std::vector<udt::contact>>();
    const auto contact_json = big_json["contacts"].at(0);
    const auto contact = contact_json.get<udt::contact>();
    const auto person = contact_json["person"].get<udt::person>();
    const auto address = contact_json["address"].get<udt::address>();
    const auto age = contact_json["person"]["age"].get<udt::age>();
    const auto name = contact_json["person"]["name"].get<udt::name>();

    CHECK(age == a);
    CHECK(name == n);
    CHECK(address == addr);
    CHECK(person == sfinae_addict);
    CHECK(contact == cpp_programmer);
    CHECK(contacts == book.m_contacts);
    CHECK(book_name == udt::name{"C++"});
    CHECK(book == parsed_book);
  }
}
<commit_msg>add more tests to unit-udt.cpp<commit_after>/*
    __ _____ _____ _____
 __|  |   __|     |   | |  JSON for Modern C++ (test suite)
|  |  |__   |  |  | | | |  version 2.0.7
|_____|_____|_____|_|___|  https://github.com/nlohmann/json

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.

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

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

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

#include <array>
#include <string>
#include <memory>
#include "catch.hpp"

#include "json.hpp"

namespace udt
{
  struct age
  {
    int m_val;
  };

  struct name
  {
    std::string m_val;
  };

  struct address
  {
    std::string m_val;
  };

  struct person
  {
    age m_age;
    name m_name;
  };

  struct contact
  {
    person m_person;
    address m_address;
  };

  struct contact_book
  {
    name m_book_name;
    std::vector<contact> m_contacts;
  };
}

// to_json methods for default basic_json
namespace udt
{
  void to_json(nlohmann::json& j, age a)
  {
    j = a.m_val;
  }

  void to_json(nlohmann::json& j, name const& n)
  {
    j = n.m_val;
  }

  void to_json(nlohmann::json& j, person const& p)
  {
    using nlohmann::json;
    j = json{{"age", p.m_age}, {"name", p.m_name}};
  }

  void to_json(nlohmann::json& j, address const& a)
  {
    j = a.m_val;
  }

  void to_json(nlohmann::json& j, contact const& c)
  {
    using nlohmann::json;
    j = json{{"person", c.m_person}, {"address", c.m_address}};
  }

  void to_json(nlohmann::json& j, contact_book const& cb)
  {
    using nlohmann::json;
    j = json{{"name", cb.m_book_name}, {"contacts", cb.m_contacts}};
  }

  // operators
  bool operator==(age lhs, age rhs)
  {
    return lhs.m_val == rhs.m_val;
  }

  bool operator==(address const &lhs, address const &rhs)
  {
    return lhs.m_val == rhs.m_val;
  }

  bool operator==(name const &lhs, name const &rhs)
  {
    return lhs.m_val == rhs.m_val;
  }

  bool operator==(person const &lhs, person const &rhs)
  {
    return std::tie(lhs.m_name, lhs.m_age) == std::tie(rhs.m_name, rhs.m_age);
  }

  bool operator==(contact const &lhs, contact const &rhs)
  {
    return std::tie(lhs.m_person, lhs.m_address) ==
           std::tie(rhs.m_person, rhs.m_address);
  }

  bool operator==(contact_book const &lhs, contact_book const &rhs)
  {
    return std::tie(lhs.m_book_name, lhs.m_contacts) ==
           std::tie(rhs.m_book_name, rhs.m_contacts);
  }
}

// from_json methods for default basic_json
namespace udt
{
  void from_json(nlohmann::json const& j, age &a)
  {
    a.m_val = j.get<int>();
  }

  void from_json(nlohmann::json const& j, name &n)
  {
    n.m_val = j.get<std::string>();
  }

  void from_json(nlohmann::json const& j, person &p)
  {
    p.m_age = j["age"].get<age>();
    p.m_name = j["name"].get<name>();
  }

  void from_json(nlohmann::json const &j, address &a)
  {
    a.m_val = j.get<std::string>();
  }

  void from_json(nlohmann::json const& j, contact &c)
  {
    c.m_person = j["person"].get<person>();
    c.m_address = j["address"].get<address>();
  }

  void from_json(nlohmann::json const&j, contact_book &cb)
  {
    cb.m_book_name = j["name"].get<name>();
    cb.m_contacts = j["contacts"].get<std::vector<contact>>();
  }
}

TEST_CASE("basic usage", "[udt]")
{
  using nlohmann::json;

  // a bit narcissic maybe :) ?
  const udt::age a{23};
  const udt::name n{"theo"};
  const udt::person sfinae_addict{a, n};
  const udt::address addr{"Paris"};
  const udt::contact cpp_programmer{sfinae_addict, addr};
  const udt::contact_book book{{"C++"}, {cpp_programmer, cpp_programmer}};

  SECTION("conversion to json via free-functions")
  {
    CHECK(json(a) == json(23));
    CHECK(json(n) == json("theo"));
    CHECK(json(sfinae_addict) == R"({"name":"theo", "age":23})"_json);
    CHECK(json("Paris") == json(addr));
    CHECK(json(cpp_programmer) ==
          R"({"person" : {"age":23, "name":"theo"}, "address":"Paris"})"_json);

    CHECK(
        json(book) ==
        R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo"}, "address":"Paris"}, {"person" : {"age":23, "name":"theo"}, "address":"Paris"}]})"_json);
  }

  SECTION("conversion from json via free-functions")
  {
    const auto big_json =
        R"({"name":"C++", "contacts" : [{"person" : {"age":23, "name":"theo"}, "address":"Paris"}, {"person" : {"age":23, "name":"theo"}, "address":"Paris"}]})"_json;
    const auto parsed_book = big_json.get<udt::contact_book>();
    const auto book_name = big_json["name"].get<udt::name>();
    const auto contacts = big_json["contacts"].get<std::vector<udt::contact>>();
    const auto contact_json = big_json["contacts"].at(0);
    const auto contact = contact_json.get<udt::contact>();
    const auto person = contact_json["person"].get<udt::person>();
    const auto address = contact_json["address"].get<udt::address>();
    const auto age = contact_json["person"]["age"].get<udt::age>();
    const auto name = contact_json["person"]["name"].get<udt::name>();

    CHECK(age == a);
    CHECK(name == n);
    CHECK(address == addr);
    CHECK(person == sfinae_addict);
    CHECK(contact == cpp_programmer);
    CHECK(contacts == book.m_contacts);
    CHECK(book_name == udt::name{"C++"});
    CHECK(book == parsed_book);
  }
}

namespace udt
{
template <typename T>
class optional_type
{
public:
  optional_type() = default;
  optional_type(T t) { _impl = std::make_shared<T>(std::move(t)); }
  optional_type(std::nullptr_t) { _impl = nullptr; }

  optional_type &operator=(std::nullptr_t)
  {
    _impl = nullptr;
    return *this;
  }

  optional_type& operator=(T t)
  {
    _impl = std::make_shared<T>(std::move(t));
    return *this;
  }

  explicit operator bool() const noexcept { return _impl != nullptr; }
  T const &operator*() const noexcept { return *_impl; }
  T &operator*() noexcept { return *_impl; }

private:
  std::shared_ptr<T> _impl;
};

struct legacy_type
{
  std::string number;
};
}

namespace nlohmann
{
template <typename T>
struct adl_serializer<udt::optional_type<T>>
{
  static void to_json(json& j, udt::optional_type<T> const& opt)
  {
    if (opt)
      j = *opt;
    else
      j = nullptr;
  }

  static void from_json(json const &j, udt::optional_type<T> &opt)
  {
    if (j.is_null())
      opt = nullptr;
    else
      opt = j.get<T>();
  }
};

template <>
struct adl_serializer<udt::legacy_type>
{
  static void to_json(json& j, udt::legacy_type const& l)
  {
    j = std::stoi(l.number);
  }

  static void from_json(json const& j, udt::legacy_type& l)
  {
    l.number = std::to_string(j.get<int>());
  }
};
}

TEST_CASE("adl_serializer specialization", "[udt]")
{
  using nlohmann::json;

  SECTION("partial specialization")
  {
    SECTION("to_json")
    {
      udt::optional_type<udt::person> optPerson;

      json j = optPerson;
      CHECK(j.is_null());

      optPerson = udt::person{{42}, {"John Doe"}};
      j = optPerson;
      CHECK_FALSE(j.is_null());

      CHECK(j.get<udt::person>() == *optPerson);
    }

    SECTION("from_json")
    {
      auto person = udt::person{{42}, {"John Doe"}};
      json j = person;

      auto optPerson = j.get<udt::optional_type<udt::person>>();
      REQUIRE(optPerson);
      CHECK(*optPerson == person);

      j = nullptr;
      optPerson = j.get<udt::optional_type<udt::person>>();
      CHECK(!optPerson);
    }
  }

  SECTION("total specialization")
  {
    SECTION("to_json")
    {
      udt::legacy_type lt{"4242"};

      json j = lt;
      CHECK(j.get<int>() == 4242);
    }

    SECTION("from_json")
    {
      json j = 4242;
      auto lt = j.get<udt::legacy_type>();
      CHECK(lt.number == "4242");
    }
  }
}
<|endoftext|>