<commit_before>/* Copyright (c) 2017, CNRS-LAAS
All rights reserved.

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

 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

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

#ifndef PLANNING_CPP_UAV_H
#define PLANNING_CPP_UAV_H

#include <vector>
#include <cassert>
#include "../ext/dubins.h"
#include "waypoint.hpp"
#include "../utils.hpp"
#include "dubins3d.hpp"
#include "dubinswind.hpp"

namespace SAOP {

    struct UAV {

        UAV(const double max_air_speed, const double max_angular_velocity, const double max_pitch_angle) :
                _max_angular_velocity(max_angular_velocity),
                _max_air_speed(max_air_speed),
                _min_turn_radius(max_air_speed / max_angular_velocity),
                _max_pitch_angle(max_pitch_angle) {}

        UAV(const UAV& uav) = default;

        double max_angular_velocity() const {
            return _max_angular_velocity;
        }

        double max_air_speed() const {
            return _max_air_speed;
        }

        double min_turn_radius() const {
            return _min_turn_radius;
        }

        double max_pitch_angle() const {
            return _max_pitch_angle;
        }

        double view_width() const {
            return _view_width;
        }

        double view_depth() const {
            return _view_depth;
        }

        /** Returns the Dubins travel distance between the two waypoints. */
        double travel_distance(const Waypoint& origin, const Waypoint& target) const {
            DubinsPath path = dubins_path(origin, target);
            return dubins_path_length(&path);
        }

        /** Returns the Dubins travel distance between the two waypoints. */
        double travel_distance(const Waypoint3d& origin, const Waypoint3d& target) const {
            Dubins3dPathLength path(origin, target, _min_turn_radius, _max_pitch_angle);
            return path.L;
        }

        /** Returns the travel time between the two waypoints. */
        double travel_time(const Waypoint& origin, const Waypoint& target) const {
            return travel_distance(origin, target) / _max_air_speed;
        }

        /** Returns the travel time between the two waypoints. */
        double travel_time(const Waypoint3d& origin, const Waypoint3d& target) const {
            return travel_distance(origin, target) / _max_air_speed;
        }

        /** Returns the travel time between the two waypoints. */
        double travel_time(const Waypoint3d& origin, const Waypoint3d& target, const WindVector& wind) const {
            try {
                DubinsWind path(origin, target, wind, _min_turn_radius, _max_pitch_angle);
                return path.T();
            } catch (const DubinsWindPathNotFoundException&) {
                return std::numeric_limits<double>::infinity();
            }
        }

        /* Determine whether the UAV is turning*/
        bool is_turning(const Waypoint3d& prev, const Waypoint3d& current) const {
            // r = dist(prev, current) / (current.dir - prev.dir)
            // roll = atan(v^2/(r*g))
            return !ALMOST_EQUAL(prev.dir, current.dir);
        }

        /** Returns a sequence of waypoints following the dubins trajectory, one every step_size distance units. */
        std::vector<Waypoint>
        path_sampling(const Waypoint& origin, const Waypoint& target, double step_size) const {
            ASSERT(step_size > 0);
            const double length = travel_distance(origin, target);
            DubinsPath path = dubins_path(origin, target);
            std::vector<Waypoint> waypoints;
            for (double it = 0; it < length; it += step_size) {
                double q[3];
                dubins_path_sample(&path, it, q);
                Waypoint wp(q[0], q[1], q[2]);
                waypoints.push_back(wp);
            }
            waypoints.push_back(target);
            return waypoints;
        }

        /** Returns a sequence of waypoints following the dubins trajectory, one every step_size distance units. */
        std::vector<Waypoint3d>
        path_sampling(const Waypoint3d& origin, const Waypoint3d& target, double step_size) const {
            ASSERT(step_size > 0);
            Dubins3dPath path = Dubins3dPath(origin, target, _min_turn_radius, _max_pitch_angle);
            std::vector<Waypoint3d> waypoints;
            for (double it = 0; it < path.L_2d; it += step_size) {
                waypoints.push_back(path.sample(it));
            }
            waypoints.push_back(target);
            return waypoints;
        }

        /** Returns a sequence of waypoints following the dubins trajectory, one every step_size distance units. */
        std::vector<Waypoint3d>
        path_sampling(const Waypoint3d& origin, const Waypoint3d& target, const WindVector& wind,
                      double step_size) const {
            ASSERT(step_size > 0);
            DubinsWind path = DubinsWind(origin, target, wind, _max_air_speed, _min_turn_radius);
            return path.sampled(step_size);
        }

        /** Returns a sequence of waypoints following the dubins trajectory, one every step_size distance units. */
        std::vector<Waypoint3d>
        path_sampling_airframe(const Waypoint3d& origin, const Waypoint3d& target, const WindVector& wind,
                               double step_size) const {
            ASSERT(step_size > 0);
            DubinsWind path = DubinsWind(origin, target, wind, _max_air_speed, _min_turn_radius);
            return path.sampled_airframe(step_size);
        }

        /* Returns a sequence of waypoints with its corresponding time following the dubins trajectory,
         * one every step_size distance units. */
        std::pair<std::vector<Waypoint3d>, std::vector<double>>
        path_sampling_with_time(const Waypoint3d& origin, const Waypoint3d& target, double step_size,
                                double t_start) const {
            ASSERT(step_size > 0);
            Dubins3dPath path = Dubins3dPath(origin, target, _min_turn_radius, _max_pitch_angle);
            std::vector<Waypoint3d> waypoints;
            std::vector<double> times;

            for (double it = 0; it < path.L_2d; it += step_size) {
                waypoints.push_back(path.sample(it));
                times.push_back(t_start + it / _max_air_speed);
            }
            waypoints.push_back(target);
            times.push_back(t_start + path.L_2d / _max_air_speed);
            return {waypoints, times};
        }

        /** Rotates the given segment on the center of the visibility area. */
        Segment rotate_on_visibility_center(const Segment& segment, double target_dir) const {
            const double visibility_depth = segment.length + _view_depth;
            const double vis_center_x = segment.start.x + cos(segment.start.dir) * visibility_depth / 2;
            const double vis_center_y = segment.start.y + sin(segment.start.dir) * visibility_depth / 2;
            const double new_segment_start_x = vis_center_x - cos(target_dir) * visibility_depth / 2;
            const double new_segment_start_y = vis_center_y - sin(target_dir) * visibility_depth / 2;

            return Segment(Waypoint(new_segment_start_x, new_segment_start_y, target_dir), segment.length);
        }

        /** Rotates the given segment on the center of the visibility area. */
        Segment3d rotate_on_visibility_center(const Segment3d& segment, double target_dir) const {
            ASSERT(ALMOST_EQUAL(segment.start.z, segment.end.z));
            const double visibility_depth = segment.length + _view_depth;
            const double vis_center_x = segment.start.x + cos(segment.start.dir) * visibility_depth / 2;
            const double vis_center_y = segment.start.y + sin(segment.start.dir) * visibility_depth / 2;
            const double new_segment_start_x = vis_center_x - cos(target_dir) * visibility_depth / 2;
            const double new_segment_start_y = vis_center_y - sin(target_dir) * visibility_depth / 2;
            return Segment3d(Waypoint3d(new_segment_start_x, new_segment_start_y, segment.start.z, target_dir),
                             segment.length);
        }

        /** Builds a new segment of the given length and direction,
         *  such that (x_coords, y_coords) is at the center of the visibility area. */
        Segment observation_segment(double x_coords, double y_coords, double dir, double length) const {
            const double visibility_depth = length + _view_depth;
            const double segment_start_x = x_coords - cos(dir) * visibility_depth / 2;
            const double segment_start_y = y_coords - sin(dir) * visibility_depth / 2;
            return Segment(Waypoint(segment_start_x, segment_start_y, dir), length);
        }

        /** Builds a new segment of the given length and direction,
         *  such that (x_coords, y_coords) is at the center of the visibility area. */
        Segment3d
        observation_segment(double x_coords, double y_coords, double z_coords, double dir, double length) const {
            const double visibility_depth = length + _view_depth;
            const double segment_start_x = x_coords - cos(dir) * visibility_depth / 2;
            const double segment_start_y = y_coords - sin(dir) * visibility_depth / 2;
            return Segment3d(Waypoint3d(segment_start_x, segment_start_y, z_coords, dir), length);
        }

        Waypoint visibility_center(const Segment& segment) const {
            const double visibility_depth = segment.length + _view_depth;
            const double vis_center_x = segment.start.x + cos(segment.start.dir) * visibility_depth / 2;
            const double vis_center_y = segment.start.y + sin(segment.start.dir) * visibility_depth / 2;
            return Waypoint(vis_center_x, vis_center_y, segment.start.dir);
        }

        Waypoint3d visibility_center(const Segment3d& segment) const {
            ASSERT(ALMOST_EQUAL(segment.start.z, segment.end.z));
            const double visibility_depth = segment.length + _view_depth;
            const double vis_center_x = segment.start.x + cos(segment.start.dir) * visibility_depth / 2;
            const double vis_center_y = segment.start.y + sin(segment.start.dir) * visibility_depth / 2;
            return Waypoint3d(vis_center_x, vis_center_y, segment.start.z, segment.start.dir);
        }

    private:

        double _max_angular_velocity;
        double _max_air_speed;
        double _min_turn_radius;
        double _max_pitch_angle; /* aka gamma_max */
        double _view_width = 100;
        double _view_depth = 70;

        DubinsPath dubins_path(const Waypoint& origin, const Waypoint& target) const {
            DubinsPath path;
            double orig[3] = {origin.x, origin.y, origin.dir};
            double dest[3] = {target.x, target.y, target.dir};
            // ugly hack to be compatible with dubins implementation that expects a double[3] in place of each Waypoint
            int ret = dubins_init(orig, dest, _min_turn_radius, &path);
            ASSERT(ret == 0);
            return path;
        }
    };
}
#endif //PLANNING_CPP_UAV_H
<commit_msg>Add path_sampling_with_time to UAV<commit_after>/* Copyright (c) 2017, CNRS-LAAS
All rights reserved.

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

 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

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

#ifndef PLANNING_CPP_UAV_H
#define PLANNING_CPP_UAV_H

#include <vector>
#include <cassert>
#include "../ext/dubins.h"
#include "waypoint.hpp"
#include "../utils.hpp"
#include "dubins3d.hpp"
#include "dubinswind.hpp"

namespace SAOP {

    struct UAV {

        UAV(const double max_air_speed, const double max_angular_velocity, const double max_pitch_angle) :
                _max_angular_velocity(max_angular_velocity),
                _max_air_speed(max_air_speed),
                _min_turn_radius(max_air_speed / max_angular_velocity),
                _max_pitch_angle(max_pitch_angle) {}

        UAV(const UAV& uav) = default;

        double max_angular_velocity() const {
            return _max_angular_velocity;
        }

        double max_air_speed() const {
            return _max_air_speed;
        }

        double min_turn_radius() const {
            return _min_turn_radius;
        }

        double max_pitch_angle() const {
            return _max_pitch_angle;
        }

        double view_width() const {
            return _view_width;
        }

        double view_depth() const {
            return _view_depth;
        }

        /** Returns the Dubins travel distance between the two waypoints. */
        double travel_distance(const Waypoint& origin, const Waypoint& target) const {
            DubinsPath path = dubins_path(origin, target);
            return dubins_path_length(&path);
        }

        /** Returns the Dubins travel distance between the two waypoints. */
        double travel_distance(const Waypoint3d& origin, const Waypoint3d& target) const {
            Dubins3dPathLength path(origin, target, _min_turn_radius, _max_pitch_angle);
            return path.L;
        }

        /** Returns the travel time between the two waypoints. */
        double travel_time(const Waypoint& origin, const Waypoint& target) const {
            return travel_distance(origin, target) / _max_air_speed;
        }

        /** Returns the travel time between the two waypoints. */
        double travel_time(const Waypoint3d& origin, const Waypoint3d& target) const {
            return travel_distance(origin, target) / _max_air_speed;
        }

        /** Returns the travel time between the two waypoints. */
        double travel_time(const Waypoint3d& origin, const Waypoint3d& target, const WindVector& wind) const {
            try {
                DubinsWind path(origin, target, wind, _min_turn_radius, _max_pitch_angle);
                return path.T();
            } catch (const DubinsWindPathNotFoundException&) {
                return std::numeric_limits<double>::infinity();
            }
        }

        /* Determine whether the UAV is turning*/
        bool is_turning(const Waypoint3d& prev, const Waypoint3d& current) const {
            // r = dist(prev, current) / (current.dir - prev.dir)
            // roll = atan(v^2/(r*g))
            return !ALMOST_EQUAL(prev.dir, current.dir);
        }

        /** Returns a sequence of waypoints following the dubins trajectory, one every step_size distance units. */
        std::vector<Waypoint>
        path_sampling(const Waypoint& origin, const Waypoint& target, double step_size) const {
            ASSERT(step_size > 0);
            const double length = travel_distance(origin, target);
            DubinsPath path = dubins_path(origin, target);
            std::vector<Waypoint> waypoints;
            for (double it = 0; it < length; it += step_size) {
                double q[3];
                dubins_path_sample(&path, it, q);
                Waypoint wp(q[0], q[1], q[2]);
                waypoints.push_back(wp);
            }
            waypoints.push_back(target);
            return waypoints;
        }

        /** Returns a sequence of waypoints following the dubins trajectory, one every step_size distance units. */
        std::vector<Waypoint3d>
        path_sampling(const Waypoint3d& origin, const Waypoint3d& target, double step_size) const {
            ASSERT(step_size > 0);
            Dubins3dPath path = Dubins3dPath(origin, target, _min_turn_radius, _max_pitch_angle);
            std::vector<Waypoint3d> waypoints;
            for (double it = 0; it < path.L_2d; it += step_size) {
                waypoints.push_back(path.sample(it));
            }
            waypoints.push_back(target);
            return waypoints;
        }

        /** Returns a sequence of waypoints following the dubins trajectory, one every step_size distance units. */
        std::vector<Waypoint3d>
        path_sampling(const Waypoint3d& origin, const Waypoint3d& target, const WindVector& wind,
                      double step_size) const {
            ASSERT(step_size > 0);
            DubinsWind path = DubinsWind(origin, target, wind, _max_air_speed, _min_turn_radius);
            return path.sampled(step_size);
        }

        /** Returns a sequence of waypoints following the dubins trajectory, one every step_size distance units. */
        std::vector<Waypoint3d>
        path_sampling_airframe(const Waypoint3d& origin, const Waypoint3d& target, const WindVector& wind,
                               double step_size) const {
            ASSERT(step_size > 0);
            DubinsWind path = DubinsWind(origin, target, wind, _max_air_speed, _min_turn_radius);
            return path.sampled_airframe(step_size);
        }

        /* Returns a sequence of waypoints with its corresponding time following the dubins trajectory,
         * one every step_size distance units. */
        std::pair<std::vector<Waypoint3d>, std::vector<double>>
        path_sampling_with_time(const Waypoint3d& origin, const Waypoint3d& target, double step_size,
                                double t_start) const {
            ASSERT(step_size > 0);
            Dubins3dPath path = Dubins3dPath(origin, target, _min_turn_radius, _max_pitch_angle);
            std::vector<Waypoint3d> waypoints;
            std::vector<double> times;

            for (double it = 0; it < path.L_2d; it += step_size) {
                waypoints.push_back(path.sample(it));
                times.push_back(t_start + it / _max_air_speed);
            }
            waypoints.push_back(target);
            times.push_back(t_start + path.L_2d / _max_air_speed);
            return {waypoints, times};
        }

        /* Returns a sequence of waypoints with its corresponding time following the dubins trajectory,
         * one every step_size distance units. */
        std::pair<std::vector<Waypoint3d>, std::vector<double>>
        path_sampling_with_time(const Waypoint3d& origin, const Waypoint3d& target, const WindVector& wind,
                                double step_size, double t_start) const {
            ASSERT(step_size > 0);
            DubinsWind path = DubinsWind(origin, target, wind, _max_air_speed, _min_turn_radius);
            auto wp_time = path.sampled_with_time(step_size);
            auto& t = std::get<1>(wp_time);
            for (auto it = t.begin(); it != t.end(); ++it) {
                *it += t_start;
            }
            return wp_time;

        }

        /** Rotates the given segment on the center of the visibility area. */
        Segment rotate_on_visibility_center(const Segment& segment, double target_dir) const {
            const double visibility_depth = segment.length + _view_depth;
            const double vis_center_x = segment.start.x + cos(segment.start.dir) * visibility_depth / 2;
            const double vis_center_y = segment.start.y + sin(segment.start.dir) * visibility_depth / 2;
            const double new_segment_start_x = vis_center_x - cos(target_dir) * visibility_depth / 2;
            const double new_segment_start_y = vis_center_y - sin(target_dir) * visibility_depth / 2;

            return Segment(Waypoint(new_segment_start_x, new_segment_start_y, target_dir), segment.length);
        }

        /** Rotates the given segment on the center of the visibility area. */
        Segment3d rotate_on_visibility_center(const Segment3d& segment, double target_dir) const {
            ASSERT(ALMOST_EQUAL(segment.start.z, segment.end.z));
            const double visibility_depth = segment.length + _view_depth;
            const double vis_center_x = segment.start.x + cos(segment.start.dir) * visibility_depth / 2;
            const double vis_center_y = segment.start.y + sin(segment.start.dir) * visibility_depth / 2;
            const double new_segment_start_x = vis_center_x - cos(target_dir) * visibility_depth / 2;
            const double new_segment_start_y = vis_center_y - sin(target_dir) * visibility_depth / 2;
            return Segment3d(Waypoint3d(new_segment_start_x, new_segment_start_y, segment.start.z, target_dir),
                             segment.length);
        }

        /** Builds a new segment of the given length and direction,
         *  such that (x_coords, y_coords) is at the center of the visibility area. */
        Segment observation_segment(double x_coords, double y_coords, double dir, double length) const {
            const double visibility_depth = length + _view_depth;
            const double segment_start_x = x_coords - cos(dir) * visibility_depth / 2;
            const double segment_start_y = y_coords - sin(dir) * visibility_depth / 2;
            return Segment(Waypoint(segment_start_x, segment_start_y, dir), length);
        }

        /** Builds a new segment of the given length and direction,
         *  such that (x_coords, y_coords) is at the center of the visibility area. */
        Segment3d
        observation_segment(double x_coords, double y_coords, double z_coords, double dir, double length) const {
            const double visibility_depth = length + _view_depth;
            const double segment_start_x = x_coords - cos(dir) * visibility_depth / 2;
            const double segment_start_y = y_coords - sin(dir) * visibility_depth / 2;
            return Segment3d(Waypoint3d(segment_start_x, segment_start_y, z_coords, dir), length);
        }

        Waypoint visibility_center(const Segment& segment) const {
            const double visibility_depth = segment.length + _view_depth;
            const double vis_center_x = segment.start.x + cos(segment.start.dir) * visibility_depth / 2;
            const double vis_center_y = segment.start.y + sin(segment.start.dir) * visibility_depth / 2;
            return Waypoint(vis_center_x, vis_center_y, segment.start.dir);
        }

        Waypoint3d visibility_center(const Segment3d& segment) const {
            ASSERT(ALMOST_EQUAL(segment.start.z, segment.end.z));
            const double visibility_depth = segment.length + _view_depth;
            const double vis_center_x = segment.start.x + cos(segment.start.dir) * visibility_depth / 2;
            const double vis_center_y = segment.start.y + sin(segment.start.dir) * visibility_depth / 2;
            return Waypoint3d(vis_center_x, vis_center_y, segment.start.z, segment.start.dir);
        }

    private:

        double _max_angular_velocity;
        double _max_air_speed;
        double _min_turn_radius;
        double _max_pitch_angle; /* aka gamma_max */
        double _view_width = 100;
        double _view_depth = 70;

        DubinsPath dubins_path(const Waypoint& origin, const Waypoint& target) const {
            DubinsPath path;
            double orig[3] = {origin.x, origin.y, origin.dir};
            double dest[3] = {target.x, target.y, target.dir};
            // ugly hack to be compatible with dubins implementation that expects a double[3] in place of each Waypoint
            int ret = dubins_init(orig, dest, _min_turn_radius, &path);
            ASSERT(ret == 0);
            return path;
        }
    };
}
#endif //PLANNING_CPP_UAV_H
<|endoftext|>


<commit_before>#include <cstdio>

#define NOMINMAX
#include <wine/debug.h>

#include "test.h"

WINE_DEFAULT_DEBUG_CHANNEL(steambridget);

static Test t;

extern "C"
{
  void *get_real_object()
  {
    return (void *)(&t);
  }
}

Test::Test()
{
  WINE_TRACE("(this=%p)\n", this);
}

int Test::function_one(int param_one, bool param_two, const char *param_three)
{
  WINE_TRACE("(this=%p,%i,%i,\"%s\")\n", this, param_one, param_two, param_three);
  return 42;
}

bool Test::function_two(double param_one, void *param_two, float param_three)
{
  WINE_TRACE("(this=%p,%f,%p,%f)\n", this, param_one, param_two, param_three);
  return true;
}

<commit_msg>Added better TRACE debugging to the Winelib DLL.<commit_after>#include <cstdio>

#define NOMINMAX
#include <wine/debug.h>

#include "test.h"

WINE_DEFAULT_DEBUG_CHANNEL(steambridget);

static Test t;

extern "C"
{
  void *get_real_object()
  {
    return (void *)(&t);
  }
}

Test::Test()
{
  WINE_TRACE("(this=%p,vtable=%p,function_one=%p)\n", this, *((void **)(this)), &Test::function_one);
}

int Test::function_one(int param_one, bool param_two, const char *param_three)
{
  WINE_TRACE("(this=%p,%i,%i,\"%s\")\n", this, param_one, param_two, param_three);
  return 42;
}

bool Test::function_two(double param_one, void *param_two, float param_three)
{
  WINE_TRACE("(this=%p,%f|%i&%i,%p,%f)\n", this, param_one, param_one, param_two, param_three);
  return true;
}

<|endoftext|>


<commit_before>#include "line_optimizer.h"

#include <limits>
#include <algorithm>

#include "sparse_vector.h"
#include "scorer.h"

using namespace std;

typedef ErrorSurface::const_iterator ErrorIter;

// sort by increasing x-ints
struct IntervalComp {
  bool operator() (const ErrorIter& a, const ErrorIter& b) const {
    return a->x < b->x;
  }
};

double LineOptimizer::LineOptimize(
    const vector<ErrorSurface>& surfaces,
    const LineOptimizer::ScoreType type,
    float* best_score,
    const double epsilon) {
  // cerr << "MIN=" << MINIMIZE_SCORE << " MAX=" << MAXIMIZE_SCORE << "  MINE=" << type << endl;
  vector<ErrorIter> all_ints;
  for (vector<ErrorSurface>::const_iterator i = surfaces.begin();
       i != surfaces.end(); ++i) {
    const ErrorSurface& surface = *i;
    for (ErrorIter j = surface.begin(); j != surface.end(); ++j)
      all_ints.push_back(j);
  }
  sort(all_ints.begin(), all_ints.end(), IntervalComp());
  double last_boundary = all_ints.front()->x;
  ScoreP accp = all_ints.front()->delta->GetZero();
  Score *acc=accp.get();
  float& cur_best_score = *best_score;
  cur_best_score = (type == MAXIMIZE_SCORE ?
    -numeric_limits<float>::max() : numeric_limits<float>::max());
  bool left_edge = true;
  double pos = numeric_limits<double>::quiet_NaN();
  for (vector<ErrorIter>::iterator i = all_ints.begin();
       i != all_ints.end(); ++i) {
    const ErrorSegment& seg = **i;
    assert(seg.delta);
    if (seg.x - last_boundary > epsilon) {
      float sco = acc->ComputeScore();
      if ((type == MAXIMIZE_SCORE && sco > cur_best_score) ||
          (type == MINIMIZE_SCORE && sco < cur_best_score) ) {
        cur_best_score = sco;
	if (left_edge) {
	  pos = seg.x - 0.1;
	  left_edge = false;
	} else {
	  pos = last_boundary + (seg.x - last_boundary) / 2;
	}
	// cerr << "NEW BEST: " << pos << "  (score=" << cur_best_score << ")\n";
      }
      // string xx; acc->ScoreDetails(&xx); cerr << "---- " << xx;
      // cerr << "---- s=" << sco << "\n";
      last_boundary = seg.x;
    }
    // cerr << "x-boundary=" << seg.x << "\n";
    acc->PlusEquals(*seg.delta);
  }
  float sco = acc->ComputeScore();
  if ((type == MAXIMIZE_SCORE && sco > cur_best_score) ||
      (type == MINIMIZE_SCORE && sco < cur_best_score) ) {
    cur_best_score = sco;
    if (left_edge) {
      pos = 0;
    } else {
      pos = last_boundary + 1000.0;
    }
  }
  return pos;
}

void LineOptimizer::RandomUnitVector(const vector<int>& features_to_optimize,
                                     SparseVector<double>* axis,
                                     RandomNumberGenerator<boost::mt19937>* rng) {
  axis->clear();
  for (int i = 0; i < features_to_optimize.size(); ++i)
    axis->set_value(features_to_optimize[i], rng->next() - 0.5);
  (*axis) /= axis->l2norm();
}

void LineOptimizer::CreateOptimizationDirections(
     const vector<int>& features_to_optimize,
     int additional_random_directions,
     RandomNumberGenerator<boost::mt19937>* rng,
     vector<SparseVector<double> >* dirs
     , bool include_orthogonal
  ) {
  dirs->clear();
  typedef SparseVector<double> Dir;
  vector<Dir> &out=*dirs;
  int i=0;
  if (include_orthogonal)
    for (;i<features_to_optimize.size();++i) {
      Dir d;
      d.set_value(features_to_optimize[i],1.);
      out.push_back(d);
    }
  out.resize(i+additional_random_directions);
  for (;i<out.size();++i)
     RandomUnitVector(features_to_optimize, &out[i], rng);
  cerr << "Generated " << out.size() << " total axes to optimize along.\n";
}
<commit_msg>proper sampling from unit sphere<commit_after>#include "line_optimizer.h"

#include <limits>
#include <algorithm>

#include "sparse_vector.h"
#include "scorer.h"

using namespace std;

typedef ErrorSurface::const_iterator ErrorIter;

// sort by increasing x-ints
struct IntervalComp {
  bool operator() (const ErrorIter& a, const ErrorIter& b) const {
    return a->x < b->x;
  }
};

double LineOptimizer::LineOptimize(
    const vector<ErrorSurface>& surfaces,
    const LineOptimizer::ScoreType type,
    float* best_score,
    const double epsilon) {
  // cerr << "MIN=" << MINIMIZE_SCORE << " MAX=" << MAXIMIZE_SCORE << "  MINE=" << type << endl;
  vector<ErrorIter> all_ints;
  for (vector<ErrorSurface>::const_iterator i = surfaces.begin();
       i != surfaces.end(); ++i) {
    const ErrorSurface& surface = *i;
    for (ErrorIter j = surface.begin(); j != surface.end(); ++j)
      all_ints.push_back(j);
  }
  sort(all_ints.begin(), all_ints.end(), IntervalComp());
  double last_boundary = all_ints.front()->x;
  ScoreP accp = all_ints.front()->delta->GetZero();
  Score *acc=accp.get();
  float& cur_best_score = *best_score;
  cur_best_score = (type == MAXIMIZE_SCORE ?
    -numeric_limits<float>::max() : numeric_limits<float>::max());
  bool left_edge = true;
  double pos = numeric_limits<double>::quiet_NaN();
  for (vector<ErrorIter>::iterator i = all_ints.begin();
       i != all_ints.end(); ++i) {
    const ErrorSegment& seg = **i;
    assert(seg.delta);
    if (seg.x - last_boundary > epsilon) {
      float sco = acc->ComputeScore();
      if ((type == MAXIMIZE_SCORE && sco > cur_best_score) ||
          (type == MINIMIZE_SCORE && sco < cur_best_score) ) {
        cur_best_score = sco;
	if (left_edge) {
	  pos = seg.x - 0.1;
	  left_edge = false;
	} else {
	  pos = last_boundary + (seg.x - last_boundary) / 2;
	}
	// cerr << "NEW BEST: " << pos << "  (score=" << cur_best_score << ")\n";
      }
      // string xx; acc->ScoreDetails(&xx); cerr << "---- " << xx;
      // cerr << "---- s=" << sco << "\n";
      last_boundary = seg.x;
    }
    // cerr << "x-boundary=" << seg.x << "\n";
    acc->PlusEquals(*seg.delta);
  }
  float sco = acc->ComputeScore();
  if ((type == MAXIMIZE_SCORE && sco > cur_best_score) ||
      (type == MINIMIZE_SCORE && sco < cur_best_score) ) {
    cur_best_score = sco;
    if (left_edge) {
      pos = 0;
    } else {
      pos = last_boundary + 1000.0;
    }
  }
  return pos;
}

void LineOptimizer::RandomUnitVector(const vector<int>& features_to_optimize,
                                     SparseVector<double>* axis,
                                     RandomNumberGenerator<boost::mt19937>* rng) {
  axis->clear();
  for (int i = 0; i < features_to_optimize.size(); ++i)
    axis->set_value(features_to_optimize[i], rng->NextNormal(0.0,1.0));
  (*axis) /= axis->l2norm();
}

void LineOptimizer::CreateOptimizationDirections(
     const vector<int>& features_to_optimize,
     int additional_random_directions,
     RandomNumberGenerator<boost::mt19937>* rng,
     vector<SparseVector<double> >* dirs
     , bool include_orthogonal
  ) {
  dirs->clear();
  typedef SparseVector<double> Dir;
  vector<Dir> &out=*dirs;
  int i=0;
  if (include_orthogonal)
    for (;i<features_to_optimize.size();++i) {
      Dir d;
      d.set_value(features_to_optimize[i],1.);
      out.push_back(d);
    }
  out.resize(i+additional_random_directions);
  for (;i<out.size();++i)
     RandomUnitVector(features_to_optimize, &out[i], rng);
  cerr << "Generated " << out.size() << " total axes to optimize along.\n";
}
<|endoftext|>


<commit_before>#include "swift/AST/CASTBridging.h"

#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/TypeRepr.h"

using namespace swift;

template <typename T>
inline llvm::ArrayRef<T> getArrayRef(BridgedArrayRef bridged) {
  return {static_cast<const T *>(bridged.data), size_t(bridged.numElements)};
}

BridgedIdentifier
SwiftASTContext_getIdentifier(void *ctx, const uint8_t *_Nullable str, long len) {
  return const_cast<void *>(
      static_cast<ASTContext *>(ctx)
        ->getIdentifier(
          StringRef{reinterpret_cast<const char *>(str), size_t(len)})
        .getAsOpaquePointer());
}

void *SwiftImportDecl_create(void *ctx, void *dc, void *importLoc, char kind,
                             void *kindLoc, BridgedArrayRef path,
                             BridgedArrayRef pathLocs) {
  assert(path.numElements == pathLocs.numElements);
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  ImportPath::Builder importPath;
  for (auto p : llvm::zip(getArrayRef<Identifier>(path),
                          getArrayRef<SourceLoc>(pathLocs))) {
    Identifier ident;
    SourceLoc loc;
    std::tie(ident, loc) = p;
    importPath.push_back(ident, loc);
  }
  return ImportDecl::create(
      Context, static_cast<DeclContext *>(dc), *(SourceLoc *)&importLoc,
      static_cast<ImportKind>(kind), *(SourceLoc *)&kindLoc,
      std::move(importPath).get());
}

void *BridgedSourceLoc_advanced(void *loc, long len) {
  SourceLoc l = ((SourceLoc *)&loc)->getAdvancedLoc(len);
  return &l; // TODO: what?
}

void *SwiftTopLevelCodeDecl_createStmt(void *ctx, void *DC, void *startLoc,
                                       void *element, void *endLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto *S = static_cast<Stmt *>(element);
  auto Brace =
      BraceStmt::create(Context, *(SourceLoc *)&startLoc,
                        {S}, *(SourceLoc *)&endLoc,
                        /*Implicit=*/true);
  auto *TLCD =
      new (Context) TopLevelCodeDecl(static_cast<DeclContext *>(DC), Brace);
  return (Decl *)TLCD;
}

void *SwiftTopLevelCodeDecl_createExpr(void *ctx, void *DC, void *startLoc,
                                       void *element, void *endLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto *E = static_cast<Expr *>(element);
  auto Brace =
      BraceStmt::create(Context, *(SourceLoc *)&startLoc,
                        {E}, *(SourceLoc *)&endLoc,
                        /*Implicit=*/true);
  auto *TLCD =
      new (Context) TopLevelCodeDecl(static_cast<DeclContext *>(DC), Brace);
  return (Decl *)TLCD;
}

void *SwiftSequenceExpr_create(void *ctx, BridgedArrayRef exprs) {
  return SequenceExpr::create(*static_cast<ASTContext *>(ctx),
                              getArrayRef<Expr *>(exprs));
}

void *SwiftTupleExpr_create(void *ctx, void *lparen, BridgedArrayRef subs,
                            void *rparen) {
  return TupleExpr::create(
      *static_cast<ASTContext *>(ctx), *(SourceLoc *)&lparen,
      getArrayRef<Expr *>(subs), {}, {}, *(SourceLoc *)&rparen,
      /*Implicit*/ false);
}

void *SwiftFunctionCallExpr_create(void *ctx, void *fn, void *args) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  TupleExpr *TE = static_cast<TupleExpr *>(args);
  SmallVector<Argument, 8> arguments;
  for (unsigned i = 0; i < TE->getNumElements(); ++i) {
    arguments.emplace_back(TE->getElementNameLoc(i), TE->getElementName(i),
                           TE->getElement(i));
  }
  auto *argList = ArgumentList::create(Context, TE->getLParenLoc(), arguments,
                                       TE->getRParenLoc(), None,
                                       /*isImplicit*/ false);
  return CallExpr::create(Context, static_cast<Expr *>(fn), argList,
                          /*implicit*/ false);
}

void *SwiftIdentifierExpr_create(void *ctx, BridgedIdentifier base, void *loc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto name = DeclNameRef{
      swift::Identifier::getFromOpaquePointer(base)};
  Expr *E = new (Context) UnresolvedDeclRefExpr(
      name, DeclRefKind::Ordinary, DeclNameLoc{*(SourceLoc *)&loc});
  return E;
}

void *SwiftStringLiteralExpr_create(
    void *ctx, const uint8_t *_Nullable string,
    long len, void *TokenLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) StringLiteralExpr(
      StringRef{reinterpret_cast<const char *>(string), size_t(len)},
      *(SourceLoc *)&TokenLoc);
}

void *SwiftIntegerLiteralExpr_create(
    void *ctx, const uint8_t *_Nullable string, long len, void *TokenLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) IntegerLiteralExpr(
      StringRef{reinterpret_cast<const char *>(string), size_t(len)},
      *(SourceLoc *)&TokenLoc);
}

void *SwiftBooleanLiteralExpr_create(void *ctx, bool value, void *TokenLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) BooleanLiteralExpr(value, *(SourceLoc *)&TokenLoc);
}

void *SwiftVarDecl_create(void *ctx, BridgedIdentifier _Nullable nameId,
                          void *loc, bool isStatic, bool isLet, void *dc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) VarDecl(isStatic,
                               isLet ? VarDecl::Introducer::Let : VarDecl::Introducer::Var,
                               *(SourceLoc *)&loc, Identifier::getFromOpaquePointer(nameId),
                               reinterpret_cast<DeclContext *>(dc));
}

void *IfStmt_create(void *ctx, void *ifLoc, void *cond, void *_Nullable then, void *_Nullable elseLoc,
                    void *_Nullable elseStmt) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) IfStmt(*(SourceLoc *)&ifLoc, (Expr *)cond, (Stmt *)then, *(SourceLoc *)&elseLoc,
                              (Stmt *)elseStmt, None, Context);
}

void *BraceStmt_createExpr(void *ctx, void *lbloc, BridgedArrayRef elements, void *rbloc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return BraceStmt::create(Context, *(SourceLoc *)&lbloc,
                           getArrayRef<ASTNode>(elements),
                           *(SourceLoc *)&rbloc);
}

void *BraceStmt_createStmt(void *ctx, void *lbloc, BridgedArrayRef elements, void *rbloc) {
  llvm::SmallVector<ASTNode, 6> nodes;
  for (auto stmt : getArrayRef<Stmt *>(elements)) {
    nodes.push_back(stmt);
  }

  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return BraceStmt::create(Context, *(SourceLoc *)&lbloc,
                           Context.AllocateCopy(nodes),
                           *(SourceLoc *)&rbloc);
}

void *ParamDecl_create(
    void *ctx, void *loc,
    void *_Nullable argLoc, BridgedIdentifier _Nullable argName,
    void *_Nullable paramLoc, BridgedIdentifier _Nullable paramName,
    void *declContext) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) ParamDecl(*(SourceLoc *)&loc, *(SourceLoc *)&argLoc,
                                 Identifier::getFromOpaquePointer(argName),
                                 *(SourceLoc *)&paramLoc,
                                 Identifier::getFromOpaquePointer(paramName),
                                 (DeclContext *)declContext);
}

void *FuncDecl_create(void *ctx, void *staticLoc, bool isStatic, void *funcLoc,
                      BridgedIdentifier name, void *nameLoc,
                      bool isAsync, void *_Nullable asyncLoc,
                      bool throws, void *_Nullable throwsLoc,
                      void *paramLLoc, BridgedArrayRef params, void *paramRLoc,
                      void *_Nullable body, void *_Nullable returnType,
                      void *declContext) {
  auto *paramList = ParameterList::create(
      *static_cast<ASTContext *>(ctx), *(SourceLoc *)&paramLLoc,
      getArrayRef<ParamDecl *>(params), *(SourceLoc *)&paramRLoc);
  auto declName =
      DeclName(*static_cast<ASTContext *>(ctx),
               Identifier::getFromOpaquePointer(name), paramList);
  auto *out = FuncDecl::create(
      *static_cast<ASTContext *>(ctx), *(SourceLoc *)&staticLoc,
      isStatic ? StaticSpellingKind::KeywordStatic : StaticSpellingKind::None,
      *(SourceLoc *)&funcLoc, declName, *(SourceLoc *)&nameLoc, isAsync,
      *(SourceLoc *)&asyncLoc, throws, *(SourceLoc *)&throwsLoc, nullptr,
      paramList, (TypeRepr *)returnType, (DeclContext *)declContext);
  out->setBody((BraceStmt *)body, FuncDecl::BodyKind::Parsed);

  return static_cast<Decl *>(out);
}

void *SimpleIdentTypeRepr_create(void *ctx, void *loc, BridgedIdentifier id) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) SimpleIdentTypeRepr(DeclNameLoc(*(SourceLoc *)&loc),
                                           DeclNameRef(Identifier::getFromOpaquePointer(id)));
}

void *UnresolvedDotExpr_create(
    void *ctx, void *base, void *dotLoc,  BridgedIdentifier name,
    void *nameLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
      return new (Context) UnresolvedDotExpr((Expr *)base, *(SourceLoc *)&dotLoc,
                                         DeclNameRef(Identifier::getFromOpaquePointer(name)),
                                         DeclNameLoc(*(SourceLoc *)&nameLoc), false);
}

void *ClosureExpr_create(void *ctx, void *body, void *dc) {
  DeclAttributes attributes;
  SourceRange bracketRange;
  SourceLoc asyncLoc;
  SourceLoc throwsLoc;
  SourceLoc arrowLoc;
  SourceLoc inLoc;

  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto *out = new (Context) ClosureExpr(attributes, bracketRange, nullptr,
                                        nullptr, asyncLoc, throwsLoc, arrowLoc,
                                        inLoc, nullptr, 0, (DeclContext *)dc);
  out->setBody((BraceStmt *)body, true);
  return (Expr *)out;
}

void NominalTypeDecl_setMembers(void *decl, BridgedArrayRef members) {
  auto declMembers = getArrayRef<Decl *>(members);
  for (auto m : declMembers)
    ((NominalTypeDecl *)decl)->addMember(m);
}

DeclContextAndDecl StructDecl_create(
    void *ctx, void *loc, BridgedIdentifier name, void *nameLoc, void *dc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto *out = new (Context) StructDecl(SourceLoc(), // *(SourceLoc *)&loc,
                                       Identifier::getFromOpaquePointer(name),
                                       SourceLoc(), // *(SourceLoc *)&nameLoc,
                                       {}, nullptr,
                                       (DeclContext *)dc);
  out->setImplicit(); // TODO: remove this.
  return {(DeclContext *)out, (NominalTypeDecl *)out, (Decl *)out};
}

DeclContextAndDecl ClassDecl_create(
    void *ctx, void *loc, BridgedIdentifier name, void *nameLoc, void *dc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto *out = new (Context) ClassDecl(SourceLoc(), // *(SourceLoc *)&loc,
                                      Identifier::getFromOpaquePointer(name),
                                      SourceLoc(), // *(SourceLoc *)&nameLoc,
                                      {}, nullptr,
                                      (DeclContext *)dc, false);
  out->setImplicit(); // TODO: remove this.
  return {(DeclContext *)out, (NominalTypeDecl *)out, (Decl *)out};
}

void TopLevelCodeDecl_dump(void *decl) { ((TopLevelCodeDecl *)decl)->dump(); }

void Expr_dump(void *expr) { ((Expr *)expr)->dump(); }
void Decl_dump(void *expr) { ((Decl *)expr)->dump(); }
void Stmt_dump(void *expr) { ((Stmt *)expr)->dump(); }
<commit_msg>[ASTGen] Clean up casting with source locations<commit_after>#include "swift/AST/CASTBridging.h"

#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/TypeRepr.h"

using namespace swift;

template <typename T>
inline llvm::ArrayRef<T> getArrayRef(BridgedArrayRef bridged) {
  return {static_cast<const T *>(bridged.data), size_t(bridged.numElements)};
}

static SourceLoc getSourceLocFromPointer(void *loc) {
  auto smLoc = llvm::SMLoc::getFromPointer((const char *)loc);
  return SourceLoc(smLoc);
}

BridgedIdentifier
SwiftASTContext_getIdentifier(void *ctx, const uint8_t *_Nullable str, long len) {
  return const_cast<void *>(
      static_cast<ASTContext *>(ctx)
        ->getIdentifier(
          StringRef{reinterpret_cast<const char *>(str), size_t(len)})
        .getAsOpaquePointer());
}

void *SwiftImportDecl_create(void *ctx, void *dc, void *importLoc, char kind,
                             void *kindLoc, BridgedArrayRef path,
                             BridgedArrayRef pathLocs) {
  assert(path.numElements == pathLocs.numElements);
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  ImportPath::Builder importPath;
  for (auto p : llvm::zip(getArrayRef<Identifier>(path),
                          getArrayRef<SourceLoc>(pathLocs))) {
    Identifier ident;
    SourceLoc loc;
    std::tie(ident, loc) = p;
    importPath.push_back(ident, loc);
  }
  return ImportDecl::create(
      Context, static_cast<DeclContext *>(dc),
      getSourceLocFromPointer(importLoc),
      static_cast<ImportKind>(kind), getSourceLocFromPointer(kindLoc),
      std::move(importPath).get());
}

void *BridgedSourceLoc_advanced(void *loc, long len) {
  SourceLoc l = getSourceLocFromPointer(loc).getAdvancedLoc(len);
  return const_cast<void *>(l.getOpaquePointerValue());
}

void *SwiftTopLevelCodeDecl_createStmt(void *ctx, void *DC, void *startLoc,
                                       void *element, void *endLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto *S = static_cast<Stmt *>(element);
  auto Brace =
      BraceStmt::create(Context, getSourceLocFromPointer(startLoc),
                        {S}, getSourceLocFromPointer(endLoc),
                        /*Implicit=*/true);
  auto *TLCD =
      new (Context) TopLevelCodeDecl(static_cast<DeclContext *>(DC), Brace);
  return (Decl *)TLCD;
}

void *SwiftTopLevelCodeDecl_createExpr(void *ctx, void *DC, void *startLoc,
                                       void *element, void *endLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto *E = static_cast<Expr *>(element);
  auto Brace =
      BraceStmt::create(Context, getSourceLocFromPointer(startLoc),
                        {E}, getSourceLocFromPointer(endLoc),
                        /*Implicit=*/true);
  auto *TLCD =
      new (Context) TopLevelCodeDecl(static_cast<DeclContext *>(DC), Brace);
  return (Decl *)TLCD;
}

void *SwiftSequenceExpr_create(void *ctx, BridgedArrayRef exprs) {
  return SequenceExpr::create(*static_cast<ASTContext *>(ctx),
                              getArrayRef<Expr *>(exprs));
}

void *SwiftTupleExpr_create(void *ctx, void *lparen, BridgedArrayRef subs,
                            void *rparen) {
  return TupleExpr::create(
      *static_cast<ASTContext *>(ctx), getSourceLocFromPointer(lparen),
      getArrayRef<Expr *>(subs), {}, {}, getSourceLocFromPointer(rparen),
      /*Implicit*/ false);
}

void *SwiftFunctionCallExpr_create(void *ctx, void *fn, void *args) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  TupleExpr *TE = static_cast<TupleExpr *>(args);
  SmallVector<Argument, 8> arguments;
  for (unsigned i = 0; i < TE->getNumElements(); ++i) {
    arguments.emplace_back(TE->getElementNameLoc(i), TE->getElementName(i),
                           TE->getElement(i));
  }
  auto *argList = ArgumentList::create(Context, TE->getLParenLoc(), arguments,
                                       TE->getRParenLoc(), None,
                                       /*isImplicit*/ false);
  return CallExpr::create(Context, static_cast<Expr *>(fn), argList,
                          /*implicit*/ false);
}

void *SwiftIdentifierExpr_create(void *ctx, BridgedIdentifier base, void *loc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto name = DeclNameRef{
      swift::Identifier::getFromOpaquePointer(base)};
  Expr *E = new (Context) UnresolvedDeclRefExpr(
      name, DeclRefKind::Ordinary, DeclNameLoc{getSourceLocFromPointer(loc)});
  return E;
}

void *SwiftStringLiteralExpr_create(
    void *ctx, const uint8_t *_Nullable string,
    long len, void *TokenLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) StringLiteralExpr(
      StringRef{reinterpret_cast<const char *>(string), size_t(len)},
      getSourceLocFromPointer(TokenLoc));
}

void *SwiftIntegerLiteralExpr_create(
    void *ctx, const uint8_t *_Nullable string, long len, void *TokenLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) IntegerLiteralExpr(
      StringRef{reinterpret_cast<const char *>(string), size_t(len)},
      getSourceLocFromPointer(TokenLoc));
}

void *SwiftBooleanLiteralExpr_create(void *ctx, bool value, void *TokenLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) BooleanLiteralExpr(
      value, getSourceLocFromPointer(TokenLoc));
}

void *SwiftVarDecl_create(void *ctx, BridgedIdentifier _Nullable nameId,
                          void *loc, bool isStatic, bool isLet, void *dc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) VarDecl(isStatic,
                               isLet ? VarDecl::Introducer::Let : VarDecl::Introducer::Var,
                               getSourceLocFromPointer(loc),
                               Identifier::getFromOpaquePointer(nameId),
                               reinterpret_cast<DeclContext *>(dc));
}

void *IfStmt_create(void *ctx, void *ifLoc, void *cond, void *_Nullable then, void *_Nullable elseLoc,
                    void *_Nullable elseStmt) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) IfStmt(
      getSourceLocFromPointer(ifLoc), (Expr *)cond, (Stmt *)then,
      getSourceLocFromPointer(elseLoc), (Stmt *)elseStmt, None, Context);
}

void *BraceStmt_createExpr(void *ctx, void *lbloc, BridgedArrayRef elements, void *rbloc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return BraceStmt::create(Context, getSourceLocFromPointer(lbloc),
                           getArrayRef<ASTNode>(elements),
                           getSourceLocFromPointer(rbloc));
}

void *BraceStmt_createStmt(void *ctx, void *lbloc, BridgedArrayRef elements, void *rbloc) {
  llvm::SmallVector<ASTNode, 6> nodes;
  for (auto stmt : getArrayRef<Stmt *>(elements)) {
    nodes.push_back(stmt);
  }

  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return BraceStmt::create(Context, getSourceLocFromPointer(lbloc),
                           Context.AllocateCopy(nodes),
                           getSourceLocFromPointer(rbloc));
}

void *ParamDecl_create(
    void *ctx, void *loc,
    void *_Nullable argLoc, BridgedIdentifier _Nullable argName,
    void *_Nullable paramLoc, BridgedIdentifier _Nullable paramName,
    void *declContext) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) ParamDecl(getSourceLocFromPointer(loc),
                                 getSourceLocFromPointer(argLoc),
                                 Identifier::getFromOpaquePointer(argName),
                                 getSourceLocFromPointer(paramLoc),
                                 Identifier::getFromOpaquePointer(paramName),
                                 (DeclContext *)declContext);
}

void *FuncDecl_create(void *ctx, void *staticLoc, bool isStatic, void *funcLoc,
                      BridgedIdentifier name, void *nameLoc,
                      bool isAsync, void *_Nullable asyncLoc,
                      bool throws, void *_Nullable throwsLoc,
                      void *paramLLoc, BridgedArrayRef params, void *paramRLoc,
                      void *_Nullable body, void *_Nullable returnType,
                      void *declContext) {
  auto *paramList = ParameterList::create(
      *static_cast<ASTContext *>(ctx), getSourceLocFromPointer(paramLLoc),
      getArrayRef<ParamDecl *>(params), getSourceLocFromPointer(paramRLoc));
  auto declName =
      DeclName(*static_cast<ASTContext *>(ctx),
               Identifier::getFromOpaquePointer(name), paramList);
  auto *out = FuncDecl::create(
      *static_cast<ASTContext *>(ctx), getSourceLocFromPointer(staticLoc),
      isStatic ? StaticSpellingKind::KeywordStatic : StaticSpellingKind::None,
      getSourceLocFromPointer(funcLoc), declName,
      getSourceLocFromPointer(nameLoc), isAsync,
      getSourceLocFromPointer(asyncLoc), throws,
      getSourceLocFromPointer(throwsLoc), nullptr,
      paramList, (TypeRepr *)returnType, (DeclContext *)declContext);
  out->setBody((BraceStmt *)body, FuncDecl::BodyKind::Parsed);

  return static_cast<Decl *>(out);
}

void *SimpleIdentTypeRepr_create(void *ctx, void *loc, BridgedIdentifier id) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  return new (Context) SimpleIdentTypeRepr(
      DeclNameLoc(getSourceLocFromPointer(loc)),
      DeclNameRef(Identifier::getFromOpaquePointer(id)));
}

void *UnresolvedDotExpr_create(
    void *ctx, void *base, void *dotLoc,  BridgedIdentifier name,
    void *nameLoc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
      return new (Context) UnresolvedDotExpr(
          (Expr *)base, getSourceLocFromPointer(dotLoc),
          DeclNameRef(Identifier::getFromOpaquePointer(name)),
          DeclNameLoc(getSourceLocFromPointer(nameLoc)), false);
}

void *ClosureExpr_create(void *ctx, void *body, void *dc) {
  DeclAttributes attributes;
  SourceRange bracketRange;
  SourceLoc asyncLoc;
  SourceLoc throwsLoc;
  SourceLoc arrowLoc;
  SourceLoc inLoc;

  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto *out = new (Context) ClosureExpr(attributes, bracketRange, nullptr,
                                        nullptr, asyncLoc, throwsLoc, arrowLoc,
                                        inLoc, nullptr, 0, (DeclContext *)dc);
  out->setBody((BraceStmt *)body, true);
  return (Expr *)out;
}

void NominalTypeDecl_setMembers(void *decl, BridgedArrayRef members) {
  auto declMembers = getArrayRef<Decl *>(members);
  for (auto m : declMembers)
    ((NominalTypeDecl *)decl)->addMember(m);
}

DeclContextAndDecl StructDecl_create(
    void *ctx, void *loc, BridgedIdentifier name, void *nameLoc, void *dc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto *out = new (Context) StructDecl(getSourceLocFromPointer(loc),
                                       Identifier::getFromOpaquePointer(name),
                                       getSourceLocFromPointer(nameLoc),
                                       {}, nullptr,
                                       (DeclContext *)dc);
  out->setImplicit(); // TODO: remove this.
  return {(DeclContext *)out, (NominalTypeDecl *)out, (Decl *)out};
}

DeclContextAndDecl ClassDecl_create(
    void *ctx, void *loc, BridgedIdentifier name, void *nameLoc, void *dc) {
  ASTContext &Context = *static_cast<ASTContext *>(ctx);
  auto *out = new (Context) ClassDecl(getSourceLocFromPointer(loc),
                                      Identifier::getFromOpaquePointer(name),
                                      getSourceLocFromPointer(nameLoc),
                                      {}, nullptr,
                                      (DeclContext *)dc, false);
  out->setImplicit(); // TODO: remove this.
  return {(DeclContext *)out, (NominalTypeDecl *)out, (Decl *)out};
}

void TopLevelCodeDecl_dump(void *decl) { ((TopLevelCodeDecl *)decl)->dump(llvm::errs()); }

void Expr_dump(void *expr) { ((Expr *)expr)->dump(llvm::errs()); }
void Decl_dump(void *expr) { ((Decl *)expr)->dump(llvm::errs()); }
void Stmt_dump(void *expr) { ((Stmt *)expr)->dump(llvm::errs()); }
<|endoftext|>


<commit_before>#include <mtp/metadata/Library.h>
#include <mtp/ptp/Session.h>
#include <mtp/log.h>
#include <unordered_map>

namespace mtp
{
	Library::NameToObjectIdMap Library::ListAssociations(ObjectId parentId)
	{
		NameToObjectIdMap list;
		auto folders = _session->GetObjectHandles(_storage, mtp::ObjectFormat::Association, parentId);
		list.reserve(folders.ObjectHandles.size());

		for(auto id : folders.ObjectHandles)
		{
			auto name = _session->GetObjectStringProperty(id, ObjectProperty::ObjectFilename);
			list.insert(std::make_pair(name, id));
		}
		return list;
	}

	Library::Library(const mtp::SessionPtr & session): _session(session)
	{
		auto storages = _session->GetStorageIDs();
		if (storages.StorageIDs.empty())
			throw std::runtime_error("no storages found");

		_storage = storages.StorageIDs[0]; //picking up first storage.
		//zune fails to create artist/album without storage id

		{
			msg::ObjectHandles rootFolders = _session->GetObjectHandles(Session::AllStorages, mtp::ObjectFormat::Association, Session::Root);
			for (auto id : rootFolders.ObjectHandles)
			{
				auto name = _session->GetObjectStringProperty(id, ObjectProperty::ObjectFilename);
				if (name == "Artists")
					_artistsFolder = id;
				else if (name == "Albums")
					_albumsFolder = id;
				else if (name == "Music")
					_musicFolder = id;
			}
		}
		if (_artistsFolder == ObjectId())
			_artistsFolder = _session->CreateDirectory("Artists", Session::Root, _storage).ObjectId;
		if (_albumsFolder == ObjectId())
			_albumsFolder = _session->CreateDirectory("Albums", Session::Root, _storage).ObjectId;
		if (_musicFolder == ObjectId())
			_musicFolder = _session->CreateDirectory("Music", Session::Root, _storage).ObjectId;

		debug("artists folder: ", _artistsFolder.Id);
		debug("albums folder: ", _albumsFolder.Id);
		debug("music folder: ", _musicFolder.Id);

		auto musicFolders = ListAssociations(_musicFolder);

		using namespace mtp;
		{
			auto artists = _session->GetObjectHandles(Session::AllStorages, ObjectFormat::Artist, Session::Device);
			for (auto id : artists.ObjectHandles)
			{
				auto name = _session->GetObjectStringProperty(id, ObjectProperty::Name);
				debug("artist: ", name, "\t", id.Id);
				auto artist = std::make_shared<Artist>();
				artist->Id = id;
				artist->Name = name;
				auto it = musicFolders.find(name);
				if (it != musicFolders.end())
					artist->MusicFolderId = it->second;
				else
					artist->MusicFolderId = _session->CreateDirectory(name, _musicFolder, _storage).ObjectId;

				_artists.insert(std::make_pair(name, artist));
			}
		}

		std::unordered_map<ArtistPtr, NameToObjectIdMap> albumFolders;
		{
			auto albums = _session->GetObjectHandles(Session::AllStorages, ObjectFormat::AbstractAudioAlbum, Session::Device);
			for (auto id : albums.ObjectHandles)
			{
				auto name = _session->GetObjectStringProperty(id, ObjectProperty::Name);
				auto artistName = _session->GetObjectStringProperty(id, ObjectProperty::Artist);
				auto albumDate = _session->GetObjectStringProperty(id, ObjectProperty::DateAuthored);
				auto artist = GetArtist(artistName);
				if (!artist)
					error("invalid artist name in album ", name);

				debug("album: ", name, "\t", id.Id, "\t", albumDate);
				auto album = std::make_shared<Album>();
				album->Name = name;
				album->Artist = artist;
				album->Id = id;
				album->Year = ConvertDateTime(albumDate);
				if (albumFolders.find(artist) == albumFolders.end()) {
					albumFolders[artist] = ListAssociations(artist->MusicFolderId);
				}
				auto it = albumFolders.find(artist);
				if (it == albumFolders.end())
					throw std::runtime_error("no iterator after insert, internal error");

				const auto & albums = it->second;
				auto alit = albums.find(name);
				if (alit != albums.end())
					album->MusicFolderId = alit->second;
				else
					album->MusicFolderId = _session->CreateDirectory(name, artist->MusicFolderId, _storage).ObjectId;

				_albums.insert(std::make_pair(std::make_pair(artist, name), album));
			}
		}
	}

	Library::~Library()
	{ }

	Library::ArtistPtr Library::CreateArtist(const std::string & name)
	{
		if (name.empty())
			return nullptr;

		ByteArray propList;
		OutputStream os(propList);

		os.Write32(2); //number of props

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::Name));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(name);

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::ObjectFilename));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(name + ".art");

		auto artist = std::make_shared<Artist>();
		artist->MusicFolderId = _session->CreateDirectory(name, _musicFolder, _storage).ObjectId;

		artist->Name = name;
		auto response = _session->SendObjectPropList(_storage, _artistsFolder, ObjectFormat::Artist, 0, propList);
		artist->Id = response.ObjectId;

		_artists.insert(std::make_pair(name, artist));
		return artist;
	}

	Library::AlbumPtr Library::CreateAlbum(const ArtistPtr & artist, const std::string & name, int year)
	{
		if (name.empty() || !artist)
			return nullptr;

		ByteArray propList;
		OutputStream os(propList);

		os.Write32(year? 4: 3); //number of props

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::ArtistId));
		os.Write16(static_cast<u16>(DataTypeCode::Uint32));
		os.Write32(artist->Id.Id);

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::Name));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(name);

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::ObjectFilename));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(artist->Name + "--" + name + ".alb");

		if (year)
		{
			os.Write32(0); //object handle
			os.Write16(static_cast<u16>(ObjectProperty::DateAuthored));
			os.Write16(static_cast<u16>(DataTypeCode::String));
			os.WriteString(ConvertYear(year));
		}

		auto album = std::make_shared<Album>();
		album->Artist = artist;
		album->Name = name;
		album->Year = year;
		album->MusicFolderId = _session->CreateDirectory(name, artist->MusicFolderId, _storage).ObjectId;

		auto response = _session->SendObjectPropList(_storage, _albumsFolder, ObjectFormat::AbstractAudioAlbum, 0, propList);
		album->Id = response.ObjectId;

		_albums.insert(std::make_pair(std::make_pair(artist, name), album));
		return album;
	}

	ObjectId Library::CreateTrack(ArtistPtr artist, AlbumPtr album, ObjectFormat type, const std::string &name, const std::string &filename, size_t size)
	{
		ByteArray propList;
		OutputStream os(propList);

		os.Write32(3); //number of props

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::ArtistId));
		os.Write16(static_cast<u16>(DataTypeCode::Uint32));
		os.Write32(artist->Id.Id);

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::Name));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(name);

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::ObjectFilename));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(filename);

		auto response = _session->SendObjectPropList(Session::AnyStorage, Session::Device, type, size, propList);
		return response.ObjectId;
	}

}
<commit_msg>create track on given storage with given music/artist/album as parent<commit_after>#include <mtp/metadata/Library.h>
#include <mtp/ptp/Session.h>
#include <mtp/log.h>
#include <unordered_map>

namespace mtp
{
	Library::NameToObjectIdMap Library::ListAssociations(ObjectId parentId)
	{
		NameToObjectIdMap list;
		auto folders = _session->GetObjectHandles(_storage, mtp::ObjectFormat::Association, parentId);
		list.reserve(folders.ObjectHandles.size());

		for(auto id : folders.ObjectHandles)
		{
			auto name = _session->GetObjectStringProperty(id, ObjectProperty::ObjectFilename);
			list.insert(std::make_pair(name, id));
		}
		return list;
	}

	Library::Library(const mtp::SessionPtr & session): _session(session)
	{
		auto storages = _session->GetStorageIDs();
		if (storages.StorageIDs.empty())
			throw std::runtime_error("no storages found");

		_storage = storages.StorageIDs[0]; //picking up first storage.
		//zune fails to create artist/album without storage id

		{
			msg::ObjectHandles rootFolders = _session->GetObjectHandles(Session::AllStorages, mtp::ObjectFormat::Association, Session::Root);
			for (auto id : rootFolders.ObjectHandles)
			{
				auto name = _session->GetObjectStringProperty(id, ObjectProperty::ObjectFilename);
				if (name == "Artists")
					_artistsFolder = id;
				else if (name == "Albums")
					_albumsFolder = id;
				else if (name == "Music")
					_musicFolder = id;
			}
		}
		if (_artistsFolder == ObjectId())
			_artistsFolder = _session->CreateDirectory("Artists", Session::Root, _storage).ObjectId;
		if (_albumsFolder == ObjectId())
			_albumsFolder = _session->CreateDirectory("Albums", Session::Root, _storage).ObjectId;
		if (_musicFolder == ObjectId())
			_musicFolder = _session->CreateDirectory("Music", Session::Root, _storage).ObjectId;

		debug("artists folder: ", _artistsFolder.Id);
		debug("albums folder: ", _albumsFolder.Id);
		debug("music folder: ", _musicFolder.Id);

		auto musicFolders = ListAssociations(_musicFolder);

		using namespace mtp;
		{
			auto artists = _session->GetObjectHandles(Session::AllStorages, ObjectFormat::Artist, Session::Device);
			for (auto id : artists.ObjectHandles)
			{
				auto name = _session->GetObjectStringProperty(id, ObjectProperty::Name);
				debug("artist: ", name, "\t", id.Id);
				auto artist = std::make_shared<Artist>();
				artist->Id = id;
				artist->Name = name;
				auto it = musicFolders.find(name);
				if (it != musicFolders.end())
					artist->MusicFolderId = it->second;
				else
					artist->MusicFolderId = _session->CreateDirectory(name, _musicFolder, _storage).ObjectId;

				_artists.insert(std::make_pair(name, artist));
			}
		}

		std::unordered_map<ArtistPtr, NameToObjectIdMap> albumFolders;
		{
			auto albums = _session->GetObjectHandles(Session::AllStorages, ObjectFormat::AbstractAudioAlbum, Session::Device);
			for (auto id : albums.ObjectHandles)
			{
				auto name = _session->GetObjectStringProperty(id, ObjectProperty::Name);
				auto artistName = _session->GetObjectStringProperty(id, ObjectProperty::Artist);
				auto albumDate = _session->GetObjectStringProperty(id, ObjectProperty::DateAuthored);
				auto artist = GetArtist(artistName);
				if (!artist)
					error("invalid artist name in album ", name);

				debug("album: ", name, "\t", id.Id, "\t", albumDate);
				auto album = std::make_shared<Album>();
				album->Name = name;
				album->Artist = artist;
				album->Id = id;
				album->Year = ConvertDateTime(albumDate);
				if (albumFolders.find(artist) == albumFolders.end()) {
					albumFolders[artist] = ListAssociations(artist->MusicFolderId);
				}
				auto it = albumFolders.find(artist);
				if (it == albumFolders.end())
					throw std::runtime_error("no iterator after insert, internal error");

				const auto & albums = it->second;
				auto alit = albums.find(name);
				if (alit != albums.end())
					album->MusicFolderId = alit->second;
				else
					album->MusicFolderId = _session->CreateDirectory(name, artist->MusicFolderId, _storage).ObjectId;

				_albums.insert(std::make_pair(std::make_pair(artist, name), album));
			}
		}
	}

	Library::~Library()
	{ }

	Library::ArtistPtr Library::CreateArtist(const std::string & name)
	{
		if (name.empty())
			return nullptr;

		ByteArray propList;
		OutputStream os(propList);

		os.Write32(2); //number of props

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::Name));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(name);

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::ObjectFilename));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(name + ".art");

		auto artist = std::make_shared<Artist>();
		artist->MusicFolderId = _session->CreateDirectory(name, _musicFolder, _storage).ObjectId;

		artist->Name = name;
		auto response = _session->SendObjectPropList(_storage, _artistsFolder, ObjectFormat::Artist, 0, propList);
		artist->Id = response.ObjectId;

		_artists.insert(std::make_pair(name, artist));
		return artist;
	}

	Library::AlbumPtr Library::CreateAlbum(const ArtistPtr & artist, const std::string & name, int year)
	{
		if (name.empty() || !artist)
			return nullptr;

		ByteArray propList;
		OutputStream os(propList);

		os.Write32(year? 4: 3); //number of props

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::ArtistId));
		os.Write16(static_cast<u16>(DataTypeCode::Uint32));
		os.Write32(artist->Id.Id);

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::Name));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(name);

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::ObjectFilename));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(artist->Name + "--" + name + ".alb");

		if (year)
		{
			os.Write32(0); //object handle
			os.Write16(static_cast<u16>(ObjectProperty::DateAuthored));
			os.Write16(static_cast<u16>(DataTypeCode::String));
			os.WriteString(ConvertYear(year));
		}

		auto album = std::make_shared<Album>();
		album->Artist = artist;
		album->Name = name;
		album->Year = year;
		album->MusicFolderId = _session->CreateDirectory(name, artist->MusicFolderId, _storage).ObjectId;

		auto response = _session->SendObjectPropList(_storage, _albumsFolder, ObjectFormat::AbstractAudioAlbum, 0, propList);
		album->Id = response.ObjectId;

		_albums.insert(std::make_pair(std::make_pair(artist, name), album));
		return album;
	}

	ObjectId Library::CreateTrack(ArtistPtr artist, AlbumPtr album, ObjectFormat type, const std::string &name, const std::string &filename, size_t size)
	{
		ByteArray propList;
		OutputStream os(propList);

		os.Write32(3); //number of props

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::ArtistId));
		os.Write16(static_cast<u16>(DataTypeCode::Uint32));
		os.Write32(artist->Id.Id);

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::Name));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(name);

		os.Write32(0); //object handle
		os.Write16(static_cast<u16>(ObjectProperty::ObjectFilename));
		os.Write16(static_cast<u16>(DataTypeCode::String));
		os.WriteString(filename);

		auto response = _session->SendObjectPropList(_storage, album->MusicFolderId, type, size, propList);
		return response.ObjectId;
	}

}
<|endoftext|>


<commit_before>/*
 * LinkBasedFileLock.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/FileLock.hpp>

#include <errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include <set>
#include <vector>

#include <core/SafeConvert.hpp>
#include <core/Algorithm.hpp>
#include <core/Thread.hpp>
#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/FilePath.hpp>
#include <core/FileSerializer.hpp>
#include <core/system/System.hpp>

#include <boost/foreach.hpp>
#include <boost/system/error_code.hpp>

namespace rstudio {
namespace core {

namespace {

std::string pidString()
{
   PidType pid = system::currentProcessId();
   return safe_convert::numberToString((long) pid);
}

std::string makeHostName()
{
   char buffer[256];
   int status = ::gethostname(buffer, 255);
   if (status)
      LOG_ERROR(systemError(errno, ERROR_LOCATION));
   return std::string(buffer);
}

const std::string& hostName()
{
   static std::string instance = makeHostName();
   return instance;
}

std::string threadId()
{
   std::stringstream ss;
   ss << boost::this_thread::get_id();
   return ss.str().substr(2);
}

std::string proxyLockFileName()
{
   return std::string()
         + ".rstudio-lock"
         + "-" + hostName()
         + "-" + pidString()
         + "-" + threadId();

}

bool isLockFileStale(const FilePath& lockFilePath)
{
   return LinkBasedFileLock::isLockFileStale(lockFilePath);
}

} // end anonymous namespace

bool LinkBasedFileLock::isLockFileStale(const FilePath& lockFilePath)
{
   double seconds = s_timeoutInterval.total_seconds();
   double diff = ::difftime(::time(NULL), lockFilePath.lastWriteTime());
   return diff >= seconds;
}

namespace {

void cleanStaleLockfiles(const FilePath& dir)
{
   std::vector<FilePath> children;
   Error error = dir.children(&children);
   if (error)
      LOG_ERROR(error);

   BOOST_FOREACH(const FilePath& filePath, children)
   {
      if (boost::algorithm::starts_with(filePath.filename(), ".rstudio-lock") &&
          isLockFileStale(filePath))
      {
         Error error = filePath.remove();
         if (error)
            LOG_ERROR(error);
      }
   }
}

class LockRegistration : boost::noncopyable
{
public:

   void registerLock(const FilePath& lockFilePath)
   {
      LOCK_MUTEX(mutex_)
      {
         registration_.insert(lockFilePath);
      }
      END_LOCK_MUTEX
   }

   void deregisterLock(const FilePath& lockFilePath)
   {
      LOCK_MUTEX(mutex_)
      {
         registration_.erase(lockFilePath);
      }
      END_LOCK_MUTEX
   }

   void refreshLocks()
   {
      LOCK_MUTEX(mutex_)
      {
         BOOST_FOREACH(const FilePath& lockFilePath, registration_)
         {
            lockFilePath.setLastWriteTime();
         }
      }
      END_LOCK_MUTEX
   }

   void clearLocks()
   {
      LOCK_MUTEX(mutex_)
      {
         BOOST_FOREACH(const FilePath& lockFilePath, registration_)
         {
            Error error = lockFilePath.removeIfExists();
            if (error)
               LOG_ERROR(error);
         }
         registration_.clear();
      }
      END_LOCK_MUTEX
   }

private:

   boost::mutex mutex_;
   std::set<FilePath> registration_;
};

LockRegistration& lockRegistration()
{
   static LockRegistration instance;
   return instance;
}

Error writeLockFile(const FilePath& lockFilePath)
{

#ifndef _WIN32

   // generate proxy lockfile
   FilePath proxyPath = lockFilePath.parent().complete(proxyLockFileName());

   // since the proxy lockfile should be unique, it should _never_ be possible
   // for a collision to be found. if that does happen, it must be a leftover
   // from a previous process that crashed in this stage
   if (proxyPath.exists())
   {
      Error error = proxyPath.remove();
      if (error)
         LOG_ERROR(error);
   }

   // write something to the file (to ensure it's created)
   Error error = core::writeStringToFile(proxyPath, pidString());
   if (error)
      return error;
   RemoveOnExitScope scope(proxyPath, ERROR_LOCATION);

   // attempt to link to the desired location -- ignore return value
   // and just stat our original link after, as that's a more reliable
   // indicator of success on old NFS systems
   ::link(
            proxyPath.absolutePathNative().c_str(),
            lockFilePath.absolutePathNative().c_str());

   struct stat info;
   int errc = ::stat(proxyPath.absolutePathNative().c_str(), &info);
   if (errc)
      return systemError(errno, ERROR_LOCATION);

   // assume that a failure here is the result of someone else
   // acquiring the lock before we could
   if (info.st_nlink != 2)
      return fileExistsError(ERROR_LOCATION);

   return Success();

#else

   return systemError(boost::system::errc::function_not_supported, ERROR_LOCATION);

#endif
}

} // end anonymous namespace

struct LinkBasedFileLock::Impl
{
   FilePath lockFilePath;
};

LinkBasedFileLock::LinkBasedFileLock()
   : pImpl_(new Impl())
{
}

LinkBasedFileLock::~LinkBasedFileLock()
{
}

FilePath LinkBasedFileLock::lockFilePath() const
{
   return pImpl_->lockFilePath;
}

bool LinkBasedFileLock::isLocked(const FilePath& lockFilePath) const
{
   if (!lockFilePath.exists())
      return false;

   return !isLockFileStale(lockFilePath);
}

Error LinkBasedFileLock::acquire(const FilePath& lockFilePath)
{
   // if the lock file exists...
   if (lockFilePath.exists())
   {
      // ... and it's stale, it's a leftover lock from a previously
      // (crashed?) process. remove it and acquire our own lock
      if (isLockFileStale(lockFilePath))
      {
         // note that multiple processes may attempt to remove this
         // file at the same time, so errors shouldn't be fatal
         Error error = lockFilePath.remove();
         if (error)
            LOG_ERROR(error);
      }

      // ... it's not stale -- someone else has the lock, cannot proceed
      else
      {
         return fileExistsError(ERROR_LOCATION);
      }
   }

   // ensure the parent directory exists
   Error error = lockFilePath.parent().ensureDirectory();
   if (error)
      return error;

   // write the lock file -- this step _must_ be atomic and so only one
   // competing process should be able to succeed here
   error = writeLockFile(lockFilePath);
   if (error)
      return error;

   // clean any other stale lockfiles in that directory
   cleanStaleLockfiles(lockFilePath.parent());

   // register our lock (for refresh)
   pImpl_->lockFilePath = lockFilePath;
   lockRegistration().registerLock(lockFilePath);
   return Success();
}

Error LinkBasedFileLock::release()
{
   const FilePath& lockFilePath = pImpl_->lockFilePath;

   Error error = lockFilePath.remove();
   if (error)
      LOG_ERROR(error);

   pImpl_->lockFilePath = FilePath();
   lockRegistration().deregisterLock(lockFilePath);
   return error;
}

void LinkBasedFileLock::refresh()
{
   lockRegistration().refreshLocks();
}

void LinkBasedFileLock::cleanUp()
{
   lockRegistration().clearLocks();
}

} // namespace core
} // namespace rstudio
<commit_msg>protect lockfiles with a guid<commit_after>/*
 * LinkBasedFileLock.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/FileLock.hpp>

#include <errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include <set>
#include <vector>

#include <core/SafeConvert.hpp>
#include <core/Algorithm.hpp>
#include <core/Thread.hpp>
#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/FilePath.hpp>
#include <core/FileSerializer.hpp>
#include <core/system/System.hpp>

#include <boost/foreach.hpp>
#include <boost/system/error_code.hpp>

namespace rstudio {
namespace core {

namespace {

const char * const kFileLockGuid = "22341c29-6541-44eb-88da-e097378a46d4";

std::string pidString()
{
   PidType pid = system::currentProcessId();
   return safe_convert::numberToString((long) pid);
}

std::string makeHostName()
{
   char buffer[256];
   int status = ::gethostname(buffer, 255);
   if (status)
      LOG_ERROR(systemError(errno, ERROR_LOCATION));
   return std::string(buffer);
}

const std::string& hostName()
{
   static std::string instance = makeHostName();
   return instance;
}

std::string threadId()
{
   std::stringstream ss;
   ss << boost::this_thread::get_id();
   return ss.str().substr(2);
}

std::string proxyLockFileName()
{
   return std::string()
         + ".rstudio-lock"
         + "-" + kFileLockGuid
         + "-" + hostName()
         + "-" + pidString()
         + "-" + threadId();

}

bool isLockFileStale(const FilePath& lockFilePath)
{
   return LinkBasedFileLock::isLockFileStale(lockFilePath);
}

} // end anonymous namespace

bool LinkBasedFileLock::isLockFileStale(const FilePath& lockFilePath)
{
   double seconds = s_timeoutInterval.total_seconds();
   double diff = ::difftime(::time(NULL), lockFilePath.lastWriteTime());
   return diff >= seconds;
}

namespace {

void cleanStaleLockfiles(const FilePath& dir)
{
   std::vector<FilePath> children;
   Error error = dir.children(&children);
   if (error)
      LOG_ERROR(error);

   BOOST_FOREACH(const FilePath& filePath, children)
   {
      if (boost::algorithm::starts_with(filePath.filename(), ".rstudio-lock") &&
          isLockFileStale(filePath))
      {
         Error error = filePath.remove();
         if (error)
            LOG_ERROR(error);
      }
   }
}

class LockRegistration : boost::noncopyable
{
public:

   void registerLock(const FilePath& lockFilePath)
   {
      LOCK_MUTEX(mutex_)
      {
         registration_.insert(lockFilePath);
      }
      END_LOCK_MUTEX
   }

   void deregisterLock(const FilePath& lockFilePath)
   {
      LOCK_MUTEX(mutex_)
      {
         registration_.erase(lockFilePath);
      }
      END_LOCK_MUTEX
   }

   void refreshLocks()
   {
      LOCK_MUTEX(mutex_)
      {
         BOOST_FOREACH(const FilePath& lockFilePath, registration_)
         {
            lockFilePath.setLastWriteTime();
         }
      }
      END_LOCK_MUTEX
   }

   void clearLocks()
   {
      LOCK_MUTEX(mutex_)
      {
         BOOST_FOREACH(const FilePath& lockFilePath, registration_)
         {
            Error error = lockFilePath.removeIfExists();
            if (error)
               LOG_ERROR(error);
         }
         registration_.clear();
      }
      END_LOCK_MUTEX
   }

private:

   boost::mutex mutex_;
   std::set<FilePath> registration_;
};

LockRegistration& lockRegistration()
{
   static LockRegistration instance;
   return instance;
}

Error writeLockFile(const FilePath& lockFilePath)
{

#ifndef _WIN32

   // generate proxy lockfile
   FilePath proxyPath = lockFilePath.parent().complete(proxyLockFileName());

   // since the proxy lockfile should be unique, it should _never_ be possible
   // for a collision to be found. if that does happen, it must be a leftover
   // from a previous process that crashed in this stage
   if (proxyPath.exists())
   {
      Error error = proxyPath.remove();
      if (error)
         LOG_ERROR(error);
   }

   // write something to the file (to ensure it's created)
   Error error = core::writeStringToFile(proxyPath, pidString());
   if (error)
      return error;
   RemoveOnExitScope scope(proxyPath, ERROR_LOCATION);

   // attempt to link to the desired location -- ignore return value
   // and just stat our original link after, as that's a more reliable
   // indicator of success on old NFS systems
   ::link(
            proxyPath.absolutePathNative().c_str(),
            lockFilePath.absolutePathNative().c_str());

   struct stat info;
   int errc = ::stat(proxyPath.absolutePathNative().c_str(), &info);
   if (errc)
      return systemError(errno, ERROR_LOCATION);

   // assume that a failure here is the result of someone else
   // acquiring the lock before we could
   if (info.st_nlink != 2)
      return fileExistsError(ERROR_LOCATION);

   return Success();

#else

   return systemError(boost::system::errc::function_not_supported, ERROR_LOCATION);

#endif
}

} // end anonymous namespace

struct LinkBasedFileLock::Impl
{
   FilePath lockFilePath;
};

LinkBasedFileLock::LinkBasedFileLock()
   : pImpl_(new Impl())
{
}

LinkBasedFileLock::~LinkBasedFileLock()
{
}

FilePath LinkBasedFileLock::lockFilePath() const
{
   return pImpl_->lockFilePath;
}

bool LinkBasedFileLock::isLocked(const FilePath& lockFilePath) const
{
   if (!lockFilePath.exists())
      return false;

   return !isLockFileStale(lockFilePath);
}

Error LinkBasedFileLock::acquire(const FilePath& lockFilePath)
{
   // if the lock file exists...
   if (lockFilePath.exists())
   {
      // ... and it's stale, it's a leftover lock from a previously
      // (crashed?) process. remove it and acquire our own lock
      if (isLockFileStale(lockFilePath))
      {
         // note that multiple processes may attempt to remove this
         // file at the same time, so errors shouldn't be fatal
         Error error = lockFilePath.remove();
         if (error)
            LOG_ERROR(error);
      }

      // ... it's not stale -- someone else has the lock, cannot proceed
      else
      {
         return fileExistsError(ERROR_LOCATION);
      }
   }

   // ensure the parent directory exists
   Error error = lockFilePath.parent().ensureDirectory();
   if (error)
      return error;

   // write the lock file -- this step _must_ be atomic and so only one
   // competing process should be able to succeed here
   error = writeLockFile(lockFilePath);
   if (error)
      return error;

   // clean any other stale lockfiles in that directory
   cleanStaleLockfiles(lockFilePath.parent());

   // register our lock (for refresh)
   pImpl_->lockFilePath = lockFilePath;
   lockRegistration().registerLock(lockFilePath);
   return Success();
}

Error LinkBasedFileLock::release()
{
   const FilePath& lockFilePath = pImpl_->lockFilePath;

   Error error = lockFilePath.remove();
   if (error)
      LOG_ERROR(error);

   pImpl_->lockFilePath = FilePath();
   lockRegistration().deregisterLock(lockFilePath);
   return error;
}

void LinkBasedFileLock::refresh()
{
   lockRegistration().refreshLocks();
}

void LinkBasedFileLock::cleanUp()
{
   lockRegistration().clearLocks();
}

} // namespace core
} // namespace rstudio
<|endoftext|>


<commit_before>/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#pragma once
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/types.hpp>
#include <eosio/chain/symbol.hpp>

namespace eosio { namespace chain {

/**

asset includes amount and currency symbol

asset::from_string takes a string of the form "10.0000 CUR" and constructs an asset
with amount = 10 and symbol(4,"CUR")

*/

struct asset
{
   static constexpr int64_t max_amount = (1LL << 62) - 1;

   explicit asset(share_type a = 0, symbol id = symbol(CORE_SYMBOL)) :amount(a), sym(id) {
      EOS_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" );
      EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" );
   }

   share_type amount;
   symbol     sym;

   bool is_amount_within_range()const { return -max_amount <= amount && amount <= max_amount; }
   bool is_valid()const               { return is_amount_within_range() && sym.valid(); }

   double to_real()const { return static_cast<double>(amount) / precision(); }

   uint8_t     decimals()const;
   string      symbol_name()const;
   int64_t     precision()const;
   const symbol& get_symbol() const { return sym; }

   static asset from_string(const string& from);
   string       to_string()const;

   asset& operator += (const asset& o)
   {
      FC_ASSERT(get_symbol() == o.get_symbol());
      amount += o.amount;
      return *this;
   }

   asset& operator -= (const asset& o)
   {
      FC_ASSERT(get_symbol() == o.get_symbol());
      amount -= o.amount;
      return *this;
   }
   asset operator -()const { return asset(-amount, get_symbol()); }

   friend bool operator == (const asset& a, const asset& b)
   {
      return std::tie(a.get_symbol(), a.amount) == std::tie(b.get_symbol(), b.amount);
   }
   friend bool operator < (const asset& a, const asset& b)
   {
      FC_ASSERT(a.get_symbol() == b.get_symbol());
      return std::tie(a.amount,a.get_symbol()) < std::tie(b.amount,b.get_symbol());
   }
   friend bool operator <= (const asset& a, const asset& b) { return (a == b) || (a < b); }
   friend bool operator != (const asset& a, const asset& b) { return !(a == b); }
   friend bool operator > (const asset& a, const asset& b)  { return !(a <= b); }
   friend bool operator >= (const asset& a, const asset& b) { return !(a < b);  }

   friend asset operator - (const asset& a, const asset& b) {
      FC_ASSERT(a.get_symbol() == b.get_symbol());
      return asset(a.amount - b.amount, a.get_symbol());
   }

   friend asset operator + (const asset& a, const asset& b) {
      FC_ASSERT(a.get_symbol() == b.get_symbol());
      return asset(a.amount + b.amount, a.get_symbol());
   }

   friend std::ostream& operator << (std::ostream& out, const asset& a) { return out << a.to_string(); }

};

struct extended_asset  {
  extended_asset(){}
  extended_asset( asset a, name n ):quantity(a),contract(n){}
  asset quantity;
  name contract;
};

bool  operator <  (const asset& a, const asset& b);
bool  operator <= (const asset& a, const asset& b);

}} // namespace eosio::chain

namespace fc {
inline void to_variant(const eosio::chain::asset& var, fc::variant& vo) { vo = var.to_string(); }
inline void from_variant(const fc::variant& var, eosio::chain::asset& vo) {
   vo = eosio::chain::asset::from_string(var.get_string());
}
}

FC_REFLECT(eosio::chain::asset, (amount)(sym))
FC_REFLECT(eosio::chain::extended_asset, (quantity)(contract) )
<commit_msg>Add reflector_verify for FC_REFLECT serialization verification<commit_after>/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#pragma once
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/types.hpp>
#include <eosio/chain/symbol.hpp>

namespace eosio { namespace chain {

/**

asset includes amount and currency symbol

asset::from_string takes a string of the form "10.0000 CUR" and constructs an asset
with amount = 10 and symbol(4,"CUR")

*/

struct asset
{
   static constexpr int64_t max_amount = (1LL << 62) - 1;

   explicit asset(share_type a = 0, symbol id = symbol(CORE_SYMBOL)) :amount(a), sym(id) {
      EOS_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" );
      EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" );
   }

   bool is_amount_within_range()const { return -max_amount <= amount && amount <= max_amount; }
   bool is_valid()const               { return is_amount_within_range() && sym.valid(); }

   double to_real()const { return static_cast<double>(amount) / precision(); }

   uint8_t     decimals()const;
   string      symbol_name()const;
   int64_t     precision()const;
   const symbol& get_symbol() const { return sym; }

   static asset from_string(const string& from);
   string       to_string()const;

   asset& operator += (const asset& o)
   {
      FC_ASSERT(get_symbol() == o.get_symbol());
      amount += o.amount;
      return *this;
   }

   asset& operator -= (const asset& o)
   {
      FC_ASSERT(get_symbol() == o.get_symbol());
      amount -= o.amount;
      return *this;
   }
   asset operator -()const { return asset(-amount, get_symbol()); }

   friend bool operator == (const asset& a, const asset& b)
   {
      return std::tie(a.get_symbol(), a.amount) == std::tie(b.get_symbol(), b.amount);
   }
   friend bool operator < (const asset& a, const asset& b)
   {
      FC_ASSERT(a.get_symbol() == b.get_symbol());
      return std::tie(a.amount,a.get_symbol()) < std::tie(b.amount,b.get_symbol());
   }
   friend bool operator <= (const asset& a, const asset& b) { return (a == b) || (a < b); }
   friend bool operator != (const asset& a, const asset& b) { return !(a == b); }
   friend bool operator > (const asset& a, const asset& b)  { return !(a <= b); }
   friend bool operator >= (const asset& a, const asset& b) { return !(a < b);  }

   friend asset operator - (const asset& a, const asset& b) {
      FC_ASSERT(a.get_symbol() == b.get_symbol());
      return asset(a.amount - b.amount, a.get_symbol());
   }

   friend asset operator + (const asset& a, const asset& b) {
      FC_ASSERT(a.get_symbol() == b.get_symbol());
      return asset(a.amount + b.amount, a.get_symbol());
   }

   friend std::ostream& operator << (std::ostream& out, const asset& a) { return out << a.to_string(); }

   friend struct fc::reflector<asset>;

   void reflector_verify()const {
      EOS_ASSERT( is_amount_within_range(), asset_type_exception, "magnitude of asset amount must be less than 2^62" );
      EOS_ASSERT( sym.valid(), asset_type_exception, "invalid symbol" );
   }

private:
   share_type amount;
   symbol     sym;

};

struct extended_asset  {
  extended_asset(){}
  extended_asset( asset a, name n ):quantity(a),contract(n){}
  asset quantity;
  name contract;
};

bool  operator <  (const asset& a, const asset& b);
bool  operator <= (const asset& a, const asset& b);

}} // namespace eosio::chain

namespace fc {
inline void to_variant(const eosio::chain::asset& var, fc::variant& vo) { vo = var.to_string(); }
inline void from_variant(const fc::variant& var, eosio::chain::asset& vo) {
   vo = eosio::chain::asset::from_string(var.get_string());
}
}

FC_REFLECT(eosio::chain::asset, (amount)(sym))
FC_REFLECT(eosio::chain::extended_asset, (quantity)(contract) )
<|endoftext|>