<commit_before>#include <ros/ros.h>
#include <cv_bridge/cv_bridge.h>
#include <geometry_msgs/Point.h>
#include <geometry_msgs/PointStamped.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/video.hpp>
#include <sensor_msgs/image_encodings.h>

class ShowImage {
public:
  ShowImage()
    : m_gamma(2048),
      RGB_WINDOW_NAME {"RGB image"},
      DEPTH_WINDOW_NAME {"Depth image"},
      BINARY_WINDOW_NAME {"Binary image"}
  {
    for(int i = 0; i < 2048; i++) {
      float v = i / 2048.0;
      v = std::pow(v, 3) * 6;
      m_gamma[i] = v * 6 * 256;
    }

    cv::namedWindow(RGB_WINDOW_NAME);
    cv::namedWindow(DEPTH_WINDOW_NAME);
    cv::namedWindow(BINARY_WINDOW_NAME);
  }

  ~ShowImage() {
    cv::destroyWindow(RGB_WINDOW_NAME);
    cv::destroyWindow(DEPTH_WINDOW_NAME);
    cv::destroyWindow(BINARY_WINDOW_NAME);
  }

  void showRGB(const cv::Mat& rgb) {
    imshow(RGB_WINDOW_NAME, rgb);
  }

  void showBinary(const cv::Mat& binary) {
    imshow(BINARY_WINDOW_NAME, binary);
  }

  void showDepth(const cv::Mat& depth) {
    cv::Mat buf = cv::Mat::zeros(depth.size(), CV_16UC1);
    cv::Mat output = cv::Mat::zeros(depth.size(), CV_8UC3);
    cv::normalize(depth, buf, 0, 2013, cv::NORM_MINMAX);

    for (int i = 0; i < depth.rows * depth.cols; i++) {
      int y = (int)(i / depth.cols);
      int x = (int)(i % depth.cols);
      int pval = m_gamma[buf.at<uint16_t>(i)];
      int lb = pval & 0xff;

      switch(pval >> 8) {
      case 0:
        output.at<cv::Vec3b>(y,x)[2] = 255;
        output.at<cv::Vec3b>(y,x)[1] = 255-lb;
        output.at<cv::Vec3b>(y,x)[0] = 255-lb;
        break;
      case 1:
        output.at<cv::Vec3b>(y,x)[2] = 255;
        output.at<cv::Vec3b>(y,x)[1] = lb;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      case 2:
        output.at<cv::Vec3b>(y,x)[2] = 255-lb;
        output.at<cv::Vec3b>(y,x)[1] = 255;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      case 3:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 255;
        output.at<cv::Vec3b>(y,x)[0] = lb;
        break;
      case 4:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 255-lb;
        output.at<cv::Vec3b>(y,x)[0] = 255;
        break;
      case 5:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 0;
        output.at<cv::Vec3b>(y,x)[0] = 255-lb;
        break;
      default:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 0;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      }
    }
    imshow(DEPTH_WINDOW_NAME, output);
  }

private:
  std::vector<uint16_t> m_gamma;
  const std::string RGB_WINDOW_NAME;
  const std::string DEPTH_WINDOW_NAME;
  const std::string BINARY_WINDOW_NAME;
};

class SearchTomato {
public:
  SearchTomato()
    : tomato_contours {},
      siObj {}
  {
  }

  void update(const cv::Mat& capture_rgb) {
    siObj.showRGB(capture_rgb);
    cv::Mat binary_mat = cv::Mat::zeros(capture_rgb.size(), CV_8UC1);
    imageProsessing(capture_rgb, binary_mat);
    siObj.showBinary(binary_mat);
    searchTomatoContours(binary_mat, tomato_contours);
  }

  bool searchTomato(const cv::Mat& capture_depth, geometry_msgs::Point& tomato_point) {
    siObj.showDepth(capture_depth);
    cv::Mat maskedDepth = cv::Mat::zeros(capture_depth.size(), CV_16UC1);
    cv::Mat mask = cv::Mat::zeros(capture_depth.size(), CV_8UC1);
    cv::drawContours(mask, tomato_contours, -1, cv::Scalar(255), CV_FILLED, 8);
    siObj.showBinary(mask);

    capture_depth.copyTo(maskedDepth, mask);
    return findClosePoint(maskedDepth, tomato_point);
  }

private:
  void imageProsessing(const cv::Mat& rgb, cv::Mat& binary) {
    cv::Mat blur, hsv;
    cv::GaussianBlur(rgb, blur, cv::Size(5, 5), 4.0, 4.0);
    cv::cvtColor(blur, hsv, CV_BGR2HSV);
    redFilter(hsv, binary);
    cv::dilate(binary, binary, cv::Mat(), cv::Point(-1, -1), 2);
    cv::erode(binary, binary, cv::Mat(), cv::Point(-1, -1), 4);
    cv::dilate(binary, binary, cv::Mat(), cv::Point(-1, -1), 1);
  }

  void searchTomatoContours(const cv::Mat& binary, std::vector<std::vector<cv::Point> >& tomato_contours) {
    std::vector<std::vector<cv::Point> > contours;
    std::vector<cv::Point> contour;
    cv::Rect bounding_box;
    float ratio_balance;

    cv::findContours(binary, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

    tomato_contours.clear();
    while (!contours.empty()) {
      contour = contours.back();
      contours.pop_back();

      bounding_box = cv::boundingRect(contour);
      ratio_balance = (float)bounding_box.width / (float)bounding_box.height;
      if (ratio_balance > 1.0f) ratio_balance = 1.0f / ratio_balance;

      // delete mismach. that is smaller or spier or empty
      if (bounding_box.area() >= 400 && bounding_box.area() < cv::contourArea(contour)*2 && ratio_balance > 0.4f)
        tomato_contours.push_back(contour);
    }
  }

  void redFilter(const cv::Mat& hsv, cv::Mat& binary) {
    int a, x, y;
    for(y = 0; y < hsv.rows; y++) {
      for(x = 0; x < hsv.cols; x++) {
        a = hsv.step*y+(x*3);
        if((hsv.data[a] <= 15 || hsv.data[a] >= 300) && hsv.data[a+1] >= 30 && hsv.data[a+2] >= 50)
          binary.at<unsigned char>(y,x) = 255;
        else
          binary.at<unsigned char>(y,x) = 0;
      }
    }
  }

  bool findClosePoint(const cv::Mat& maskedDepth, geometry_msgs::Point& tomato_point) {
    uint16_t depth;
    uint16_t close_depth = 3000;

    for (int y = 0; y < maskedDepth.rows; y++) {
      const uint16_t* line_point = maskedDepth.ptr<uint16_t>(y);
      for (int x = 0; x < maskedDepth.cols; x++) {
        depth = line_point[x];
        if (512 < depth && depth <  close_depth) {
          tomato_point.x = depth; // for ros coordinate system
          tomato_point.y = x - maskedDepth.cols / 2; // for ros coordinate system
          tomato_point.z = -y + maskedDepth.rows / 2; // for ros coordinate system
          close_depth = depth;
        }
      }
    }
    return (close_depth != 4096 ? true : false);
  }

  std::vector<std::vector<cv::Point> > tomato_contours;
  ShowImage siObj;
};

class ImageConverter {
private:
  ros::NodeHandle nh;
  ros::NodeHandle tomapo_nh;
  ros::Publisher point_pub;
  geometry_msgs::Point pub_msg;
  image_transport::ImageTransport it;
  image_transport::Subscriber rgb_sub;
  image_transport::Subscriber depth_sub;
  cv_bridge::CvImageConstPtr rgb_ptr;
  cv_bridge::CvImageConstPtr depth_ptr;
  SearchTomato stObj;
  const std::size_t height_;
  const double angle_x_per_piccell_;
  const double angle_y_per_piccell_;
  static constexpr double PI {3.141592653589793};

public:
  ImageConverter(const std::size_t width, const std::size_t height, const double angle_of_view_x, const double angle_of_view_y)
    : nh {},
      tomapo_nh {nh, "tomato_point"},
      point_pub {tomapo_nh.advertise<geometry_msgs::PointStamped>("raw", 1)},
      it {nh},
      rgb_sub {it.subscribe("rgb", 1, &ImageConverter::rgbCb, this)},
      depth_sub {it.subscribe("depth", 1, &ImageConverter::depthCb, this)},
      stObj {},
      height_ {height},
      angle_x_per_piccell_ {(angle_of_view_x * PI / 180.0) / width},
      angle_y_per_piccell_ {(angle_of_view_y * PI / 180.0) / height}
  {
  }

  /**
   * search tomato function.
   * get rgb image, and search tomato.
   * will tomato_point have data.
   *
   * @author Yusuke Doi
   */
  void rgbCb(const sensor_msgs::ImageConstPtr& msg) {
    // get rgb image on kinect
    try {
      rgb_ptr = cv_bridge::toCvShare(msg, "bgr8");
    } catch (cv_bridge::Exception& e) {
      ROS_ERROR("cv_bridge exception by rgb: %s", e.what());
    }

    stObj.update(rgb_ptr->image);

    cv::waitKey(100);
  }

  void depthCb(const sensor_msgs::ImageConstPtr& msg) {
    try {
      depth_ptr = cv_bridge::toCvShare(msg, sensor_msgs::image_encodings::TYPE_16UC1);
    } catch (cv_bridge::Exception& e) {
      ROS_ERROR("cv_bridge exception by depth: %s", e.what());
    }

    if (stObj.searchTomato(depth_ptr->image, pub_msg)) {
      pub_msg.y = pub_msg.x * tan(angle_x_per_piccell_ * pub_msg.y) / 1000.0; // convert to m
      pub_msg.z = pub_msg.x * tan(angle_y_per_piccell_ * (height_ + pub_msg.z)) / 1000.0; // convert to m
      pub_msg.x = pub_msg.x / 1000.0; // convert to m
      geometry_msgs::PointStamped stamped_msg; // FIXME: rename to pub_msg
      stamped_msg.header.stamp = ros::Time::now();
      stamped_msg.header.frame_id = "kinect";
      stamped_msg.point = pub_msg;
      point_pub.publish(stamped_msg);
    }

    cv::waitKey(100);
  }
};

int main(int argc, char** argv) {
  ros::init(argc, argv, "kinect_tomato_searcher_node");
  ImageConverter ic {512, 424, 70, 60};
  ros::spin();
  return 0;
}
<commit_msg>Fix coordinate system<commit_after>#include <ros/ros.h>
#include <cv_bridge/cv_bridge.h>
#include <geometry_msgs/Point.h>
#include <geometry_msgs/PointStamped.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/video.hpp>
#include <sensor_msgs/image_encodings.h>

class ShowImage {
public:
  ShowImage()
    : m_gamma(2048),
      RGB_WINDOW_NAME {"RGB image"},
      DEPTH_WINDOW_NAME {"Depth image"},
      BINARY_WINDOW_NAME {"Binary image"}
  {
    for(int i = 0; i < 2048; i++) {
      float v = i / 2048.0;
      v = std::pow(v, 3) * 6;
      m_gamma[i] = v * 6 * 256;
    }

    cv::namedWindow(RGB_WINDOW_NAME);
    cv::namedWindow(DEPTH_WINDOW_NAME);
    cv::namedWindow(BINARY_WINDOW_NAME);
  }

  ~ShowImage() {
    cv::destroyWindow(RGB_WINDOW_NAME);
    cv::destroyWindow(DEPTH_WINDOW_NAME);
    cv::destroyWindow(BINARY_WINDOW_NAME);
  }

  void showRGB(const cv::Mat& rgb) {
    imshow(RGB_WINDOW_NAME, rgb);
  }

  void showBinary(const cv::Mat& binary) {
    imshow(BINARY_WINDOW_NAME, binary);
  }

  void showDepth(const cv::Mat& depth) {
    cv::Mat buf = cv::Mat::zeros(depth.size(), CV_16UC1);
    cv::Mat output = cv::Mat::zeros(depth.size(), CV_8UC3);
    cv::normalize(depth, buf, 0, 2013, cv::NORM_MINMAX);

    for (int i = 0; i < depth.rows * depth.cols; i++) {
      int y = (int)(i / depth.cols);
      int x = (int)(i % depth.cols);
      int pval = m_gamma[buf.at<uint16_t>(i)];
      int lb = pval & 0xff;

      switch(pval >> 8) {
      case 0:
        output.at<cv::Vec3b>(y,x)[2] = 255;
        output.at<cv::Vec3b>(y,x)[1] = 255-lb;
        output.at<cv::Vec3b>(y,x)[0] = 255-lb;
        break;
      case 1:
        output.at<cv::Vec3b>(y,x)[2] = 255;
        output.at<cv::Vec3b>(y,x)[1] = lb;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      case 2:
        output.at<cv::Vec3b>(y,x)[2] = 255-lb;
        output.at<cv::Vec3b>(y,x)[1] = 255;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      case 3:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 255;
        output.at<cv::Vec3b>(y,x)[0] = lb;
        break;
      case 4:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 255-lb;
        output.at<cv::Vec3b>(y,x)[0] = 255;
        break;
      case 5:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 0;
        output.at<cv::Vec3b>(y,x)[0] = 255-lb;
        break;
      default:
        output.at<cv::Vec3b>(y,x)[2] = 0;
        output.at<cv::Vec3b>(y,x)[1] = 0;
        output.at<cv::Vec3b>(y,x)[0] = 0;
        break;
      }
    }
    imshow(DEPTH_WINDOW_NAME, output);
  }

private:
  std::vector<uint16_t> m_gamma;
  const std::string RGB_WINDOW_NAME;
  const std::string DEPTH_WINDOW_NAME;
  const std::string BINARY_WINDOW_NAME;
};

class SearchTomato {
public:
  SearchTomato()
    : tomato_contours {},
      siObj {}
  {
  }

  void update(const cv::Mat& capture_rgb) {
    siObj.showRGB(capture_rgb);
    cv::Mat binary_mat = cv::Mat::zeros(capture_rgb.size(), CV_8UC1);
    imageProsessing(capture_rgb, binary_mat);
    siObj.showBinary(binary_mat);
    searchTomatoContours(binary_mat, tomato_contours);
  }

  bool searchTomato(const cv::Mat& capture_depth, geometry_msgs::Point& tomato_point) {
    siObj.showDepth(capture_depth);
    cv::Mat maskedDepth = cv::Mat::zeros(capture_depth.size(), CV_16UC1);
    cv::Mat mask = cv::Mat::zeros(capture_depth.size(), CV_8UC1);
    cv::drawContours(mask, tomato_contours, -1, cv::Scalar(255), CV_FILLED, 8);
    siObj.showBinary(mask);

    capture_depth.copyTo(maskedDepth, mask);
    return findClosePoint(maskedDepth, tomato_point);
  }

private:
  void imageProsessing(const cv::Mat& rgb, cv::Mat& binary) {
    cv::Mat blur, hsv;
    cv::GaussianBlur(rgb, blur, cv::Size(5, 5), 4.0, 4.0);
    cv::cvtColor(blur, hsv, CV_BGR2HSV);
    redFilter(hsv, binary);
    cv::dilate(binary, binary, cv::Mat(), cv::Point(-1, -1), 2);
    cv::erode(binary, binary, cv::Mat(), cv::Point(-1, -1), 4);
    cv::dilate(binary, binary, cv::Mat(), cv::Point(-1, -1), 1);
  }

  void searchTomatoContours(const cv::Mat& binary, std::vector<std::vector<cv::Point> >& tomato_contours) {
    std::vector<std::vector<cv::Point> > contours;
    std::vector<cv::Point> contour;
    cv::Rect bounding_box;
    float ratio_balance;

    cv::findContours(binary, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

    tomato_contours.clear();
    while (!contours.empty()) {
      contour = contours.back();
      contours.pop_back();

      bounding_box = cv::boundingRect(contour);
      ratio_balance = (float)bounding_box.width / (float)bounding_box.height;
      if (ratio_balance > 1.0f) ratio_balance = 1.0f / ratio_balance;

      // delete mismach. that is smaller or spier or empty
      if (bounding_box.area() >= 400 && bounding_box.area() < cv::contourArea(contour)*2 && ratio_balance > 0.4f)
        tomato_contours.push_back(contour);
    }
  }

  void redFilter(const cv::Mat& hsv, cv::Mat& binary) {
    int a, x, y;
    for(y = 0; y < hsv.rows; y++) {
      for(x = 0; x < hsv.cols; x++) {
        a = hsv.step*y+(x*3);
        if((hsv.data[a] <= 15 || hsv.data[a] >= 300) && hsv.data[a+1] >= 30 && hsv.data[a+2] >= 50)
          binary.at<unsigned char>(y,x) = 255;
        else
          binary.at<unsigned char>(y,x) = 0;
      }
    }
  }

  bool findClosePoint(const cv::Mat& maskedDepth, geometry_msgs::Point& tomato_point) {
    uint16_t depth;
    uint16_t close_depth = 3000;

    for (int y = 0; y < maskedDepth.rows; y++) {
      const uint16_t* line_point = maskedDepth.ptr<uint16_t>(y);
      for (int x = 0; x < maskedDepth.cols; x++) {
        depth = line_point[x];
        if (512 < depth && depth <  close_depth) {
          tomato_point.x = depth; // for ros coordinate system
          tomato_point.y = x - maskedDepth.cols / 2; // for ros coordinate system
          tomato_point.z = -(y - maskedDepth.rows / 2); // for ros coordinate system
          close_depth = depth;
        }
      }
    }
    return (close_depth != 4096 ? true : false);
  }

  std::vector<std::vector<cv::Point> > tomato_contours;
  ShowImage siObj;
};

class ImageConverter {
private:
  ros::NodeHandle nh;
  ros::NodeHandle tomapo_nh;
  ros::Publisher point_pub;
  geometry_msgs::Point pub_msg;
  image_transport::ImageTransport it;
  image_transport::Subscriber rgb_sub;
  image_transport::Subscriber depth_sub;
  cv_bridge::CvImageConstPtr rgb_ptr;
  cv_bridge::CvImageConstPtr depth_ptr;
  SearchTomato stObj;
  const std::size_t height_;
  const double angle_x_per_piccell_;
  const double angle_y_per_piccell_;
  static constexpr double PI {3.141592653589793};

public:
  ImageConverter(const std::size_t width, const std::size_t height, const double angle_of_view_x, const double angle_of_view_y)
    : nh {},
      tomapo_nh {nh, "tomato_point"},
      point_pub {tomapo_nh.advertise<geometry_msgs::PointStamped>("raw", 1)},
      it {nh},
      rgb_sub {it.subscribe("rgb", 1, &ImageConverter::rgbCb, this)},
      depth_sub {it.subscribe("depth", 1, &ImageConverter::depthCb, this)},
      stObj {},
      height_ {height},
      angle_x_per_piccell_ {(angle_of_view_x * PI / 180.0) / width},
      angle_y_per_piccell_ {(angle_of_view_y * PI / 180.0) / height}
  {
  }

  /**
   * search tomato function.
   * get rgb image, and search tomato.
   * will tomato_point have data.
   *
   * @author Yusuke Doi
   */
  void rgbCb(const sensor_msgs::ImageConstPtr& msg) {
    // get rgb image on kinect
    try {
      rgb_ptr = cv_bridge::toCvShare(msg, "bgr8");
    } catch (cv_bridge::Exception& e) {
      ROS_ERROR("cv_bridge exception by rgb: %s", e.what());
    }

    stObj.update(rgb_ptr->image);

    cv::waitKey(100);
  }

  void depthCb(const sensor_msgs::ImageConstPtr& msg) {
    try {
      depth_ptr = cv_bridge::toCvShare(msg, sensor_msgs::image_encodings::TYPE_16UC1);
    } catch (cv_bridge::Exception& e) {
      ROS_ERROR("cv_bridge exception by depth: %s", e.what());
    }

    if (stObj.searchTomato(depth_ptr->image, pub_msg)) {
      pub_msg.y = pub_msg.x * tan(angle_x_per_piccell_ * pub_msg.y) / 1000.0; // convert to m
      pub_msg.z = pub_msg.x * tan(angle_y_per_piccell_ * pub_msg.z) / 1000.0; // convert to m
      pub_msg.x = pub_msg.x / 1000.0; // convert to m
      geometry_msgs::PointStamped stamped_msg; // FIXME: rename to pub_msg
      stamped_msg.header.stamp = ros::Time::now();
      stamped_msg.header.frame_id = "kinect";
      stamped_msg.point = pub_msg;
      point_pub.publish(stamped_msg);
    }

    cv::waitKey(100);
  }
};

int main(int argc, char** argv) {
  ros::init(argc, argv, "kinect_tomato_searcher_node");
  ImageConverter ic {512, 424, 70, 60};
  ros::spin();
  return 0;
}
<|endoftext|>


<commit_before>#include "posit.h"

POSIT_UTYPE Posit::buildMask(unsigned size)
{
    POSIT_UTYPE mask = ~(POSIT_UTYPE)0;

    mask <<= POSIT_SIZE - size;
    mask >>= POSIT_SIZE - size;

    return mask;
}

Posit::Posit(unsigned nbits, unsigned es, bool nan) :
    mBits(0x0),
    mNbits(nbits),
    mEs(es),
    mNan(nan)
{
}

Posit::Posit(unsigned nbits, unsigned es) :
    Posit(nbits, es, false)
{
}

bool Posit::isZero()
{
    return mBits == 0;
}

bool Posit::isOne()
{
    POSIT_UTYPE mask = buildMask(mNbits - 1);

    return ((mBits & mask) == (POSIT_UTYPE)(1 << (mNbits - 2)));
}

bool Posit::isInf()
{
    return mBits == (POSIT_UTYPE)(1 << (mNbits - 1));
}

bool Posit::isNeg()
{
    return (mBits & (1 << (mNbits - 1))) && !isInf();
}

bool Posit::isNan()
{
    return mNan;
}

unsigned Posit::nbits()
{
    return mNbits;
}

unsigned Posit::rs()
{
    signed lastBit = -1;
    unsigned rs = 0;

    // find a bit that changes, ignoring sign bit
    for (signed i = mNbits - 2; i >= 0; i--) {
        bool bit = (mBits >> i) & 1;
        rs++;

        if (bit != lastBit && lastBit >= 0) {
            break;
        }

        lastBit = bit;
    }

    return rs;
}

unsigned Posit::es()
{
    unsigned efs = mNbits - 1 - rs();
    unsigned es = mEs < efs ? mEs : efs;

    return (es >= 0 ? es : 0);
}

unsigned Posit::fs()
{
    return mNbits - 1 - rs() - es();
}

Posit Posit::zero()
{
    return Posit(mNbits, mEs);
}

Posit Posit::inf()
{
    return zero().rec();
}

Posit Posit::nan()
{
    return Posit(mNbits, mEs, true);
}

Posit Posit::neg()
{
    Posit p = Posit(mNbits, mEs);
    POSIT_UTYPE mask = buildMask(mNbits);

    // reverse all bits and add one
    p.mBits = ((mBits ^ mask) + 1) & mask;

    return p;
}

Posit Posit::rec()
{
    Posit p = Posit(mNbits, mEs);
    POSIT_UTYPE mask = buildMask(mNbits);

    // reverse all bits but the first one and add one
    p.mBits = ((mBits ^ (mask >> 1)) + 1) & mask;

    return p;
}

Posit Posit::add(Posit& p)
{
    // fast exit
    if (isZero()) {
        return p;
    } else if (p.isZero()) {
        return *this;
    } else if (neg().eq(p)) {
        return zero();
    } else if (isInf() && p.isInf()) {
        return nan();
    } else if (isInf() || p.isInf()) {
        return inf();
    }

    // TODO implement
    return *this;
}

Posit Posit::sub(Posit& p)
{
    // no loss on negation
    Posit np = p.neg();

    return add(np);
}

Posit Posit::mul(Posit& p)
{
    // fast exit
    if (isZero()) {
        return (p.isInf() ? nan() : zero());
    } else if (p.isZero()) {
        return (isInf() ? nan() : zero());
    } else if (isOne()) {
        return (isNeg() ? p.neg() : p);
    } else if (p.isOne()) {
        return (p.isNeg() ? neg() : *this);
    } else if (isInf() || p.isInf()) {
        return inf();
    }

    // TODO implement
    return *this;
}

Posit Posit::div(Posit& p)
{
    // no loss on reciprocation!
    Posit rp = p.rec();

    return mul(rp);
}

bool Posit::eq(Posit& p)
{
    return mBits == p.mBits && !isInf();
}

bool Posit::gt(Posit& p)
{
    if (isInf() || p.isInf()) {
        // TODO throw exception
    }

    // use sign bit of the base type to perform comparison
    POSIT_STYPE xbits = mBits << (POSIT_SIZE - mNbits);
    POSIT_STYPE pbits = p.mBits << (POSIT_SIZE - mNbits);

    return xbits > pbits;
}

bool Posit::ge(Posit& p)
{
    return gt(p) || eq(p);
}

bool Posit::lt(Posit& p)
{
    return !gt(p) && !eq(p);
}

bool Posit::le(Posit& p)
{
    return !gt(p);
}

void Posit::set(int n)
{
    // TODO implement
}

void Posit::set(float n)
{
    // TODO implement
}

void Posit::set(double n)
{
    // TODO implement
}

void Posit::set(std::string& n)
{
    // TODO implement
}

void Posit::get(int& n)
{
    // TODO implement
    n = 0;
}

void Posit::get(float& n)
{
    // TODO implement
    n = 0.f;
}

void Posit::get(double& n)
{
    // TODO implement
    n = 0.;
}

void Posit::get(std::string& n)
{
    // TODO implement
    n = "0";
}

void Posit::setBits(POSIT_UTYPE bits)
{
    mBits = bits;
}

POSIT_UTYPE Posit::getBits()
{
    return mBits;
}

void Posit::print()
{
    Posit p = isNeg() ? neg() : *this;

    printf("{%d, %d} ", mNbits, mEs);

    for (signed i = mNbits - 1; i >= 0; i--) {
        printf("%d", (mBits >> i) & 1);
    }

    printf(" -> ");
    printf(isNeg() || isInf() ? "-" : "+");

    for (signed i = mNbits - 2; i >= 0; i--) {
        printf("%d", (p.mBits >> i) & 1);

        if (i > 0 &&
            (((unsigned)i == (mNbits - 1 - p.rs())) ||
             ((unsigned)i == (mNbits - 1 - p.rs() - mEs)))) {
            printf(" ");
        }
    }

    printf("\n");
}
<commit_msg>lib: consider +/-inf in eq and gt<commit_after>#include "posit.h"

POSIT_UTYPE Posit::buildMask(unsigned size)
{
    POSIT_UTYPE mask = ~(POSIT_UTYPE)0;

    mask <<= POSIT_SIZE - size;
    mask >>= POSIT_SIZE - size;

    return mask;
}

Posit::Posit(unsigned nbits, unsigned es, bool nan) :
    mBits(0x0),
    mNbits(nbits),
    mEs(es),
    mNan(nan)
{
}

Posit::Posit(unsigned nbits, unsigned es) :
    Posit(nbits, es, false)
{
}

bool Posit::isZero()
{
    return mBits == 0;
}

bool Posit::isOne()
{
    POSIT_UTYPE mask = buildMask(mNbits - 1);

    return ((mBits & mask) == (POSIT_UTYPE)(1 << (mNbits - 2)));
}

bool Posit::isInf()
{
    return mBits == (POSIT_UTYPE)(1 << (mNbits - 1));
}

bool Posit::isNeg()
{
    return (mBits & (1 << (mNbits - 1))) && !isInf();
}

bool Posit::isNan()
{
    return mNan;
}

unsigned Posit::nbits()
{
    return mNbits;
}

unsigned Posit::rs()
{
    signed lastBit = -1;
    unsigned rs = 0;

    // find a bit that changes, ignoring sign bit
    for (signed i = mNbits - 2; i >= 0; i--) {
        bool bit = (mBits >> i) & 1;
        rs++;

        if (bit != lastBit && lastBit >= 0) {
            break;
        }

        lastBit = bit;
    }

    return rs;
}

unsigned Posit::es()
{
    unsigned efs = mNbits - 1 - rs();
    unsigned es = mEs < efs ? mEs : efs;

    return (es >= 0 ? es : 0);
}

unsigned Posit::fs()
{
    return mNbits - 1 - rs() - es();
}

Posit Posit::zero()
{
    return Posit(mNbits, mEs);
}

Posit Posit::inf()
{
    return zero().rec();
}

Posit Posit::nan()
{
    return Posit(mNbits, mEs, true);
}

Posit Posit::neg()
{
    Posit p = Posit(mNbits, mEs);
    POSIT_UTYPE mask = buildMask(mNbits);

    // reverse all bits and add one
    p.mBits = ((mBits ^ mask) + 1) & mask;

    return p;
}

Posit Posit::rec()
{
    Posit p = Posit(mNbits, mEs);
    POSIT_UTYPE mask = buildMask(mNbits);

    // reverse all bits but the first one and add one
    p.mBits = ((mBits ^ (mask >> 1)) + 1) & mask;

    return p;
}

Posit Posit::add(Posit& p)
{
    // fast exit
    if (isZero()) {
        return p;
    } else if (p.isZero()) {
        return *this;
    } else if (neg().eq(p)) {
        return zero();
    } else if (isInf() && p.isInf()) {
        return nan();
    } else if (isInf() || p.isInf()) {
        return inf();
    }

    // TODO implement
    return *this;
}

Posit Posit::sub(Posit& p)
{
    // no loss on negation
    Posit np = p.neg();

    return add(np);
}

Posit Posit::mul(Posit& p)
{
    // fast exit
    if (isZero()) {
        return (p.isInf() ? nan() : zero());
    } else if (p.isZero()) {
        return (isInf() ? nan() : zero());
    } else if (isOne()) {
        return (isNeg() ? p.neg() : p);
    } else if (p.isOne()) {
        return (p.isNeg() ? neg() : *this);
    } else if (isInf() || p.isInf()) {
        return inf();
    }

    // TODO implement
    return *this;
}

Posit Posit::div(Posit& p)
{
    // no loss on reciprocation!
    Posit rp = p.rec();

    return mul(rp);
}

bool Posit::eq(Posit& p)
{
    return mBits == p.mBits;
}

bool Posit::gt(Posit& p)
{
    if (isInf() || p.isInf()) {
        return false;
    }

    // use sign bit of the base type to perform comparison
    POSIT_STYPE xbits = mBits << (POSIT_SIZE - mNbits);
    POSIT_STYPE pbits = p.mBits << (POSIT_SIZE - mNbits);

    return xbits > pbits;
}

bool Posit::ge(Posit& p)
{
    return gt(p) || eq(p);
}

bool Posit::lt(Posit& p)
{
    return !gt(p) && !eq(p);
}

bool Posit::le(Posit& p)
{
    return !gt(p);
}

void Posit::set(int n)
{
    // TODO implement
}

void Posit::set(float n)
{
    // TODO implement
}

void Posit::set(double n)
{
    // TODO implement
}

void Posit::set(std::string& n)
{
    // TODO implement
}

void Posit::get(int& n)
{
    // TODO implement
    n = 0;
}

void Posit::get(float& n)
{
    // TODO implement
    n = 0.f;
}

void Posit::get(double& n)
{
    // TODO implement
    n = 0.;
}

void Posit::get(std::string& n)
{
    // TODO implement
    n = "0";
}

void Posit::setBits(POSIT_UTYPE bits)
{
    mBits = bits;
}

POSIT_UTYPE Posit::getBits()
{
    return mBits;
}

void Posit::print()
{
    Posit p = isNeg() ? neg() : *this;

    printf("{%d, %d} ", mNbits, mEs);

    for (signed i = mNbits - 1; i >= 0; i--) {
        printf("%d", (mBits >> i) & 1);
    }

    printf(" -> ");
    printf(isNeg() || isInf() ? "-" : "+");

    for (signed i = mNbits - 2; i >= 0; i--) {
        printf("%d", (p.mBits >> i) & 1);

        if (i > 0 &&
            (((unsigned)i == (mNbits - 1 - p.rs())) ||
             ((unsigned)i == (mNbits - 1 - p.rs() - mEs)))) {
            printf(" ");
        }
    }

    printf("\n");
}
<|endoftext|>


<commit_before>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/compiler/xla/service/cpu/runtime_key_value_sort.h"

#include <algorithm>
#include <cmath>
#include <cstring>
#include <memory>
#include <string>
#include <utility>

#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
#include "tensorflow/core/platform/dynamic_annotations.h"
#include "tensorflow/core/platform/macros.h"
#include "tensorflow/core/platform/types.h"

namespace {
using tensorflow::int16;
using tensorflow::int32;
using tensorflow::int64;
using tensorflow::int8;
using tensorflow::uint16;
using tensorflow::uint32;
using tensorflow::uint64;
using tensorflow::uint8;

template <typename KeyType>
void KeyValueSort(std::pair<KeyType, int64>* row_to_sort, int64 num_elements) {
  std::sort(row_to_sort, row_to_sort + num_elements);
}

// For floating point numbers, we want a total order comparator. -NaN and NaN
// should appear at the beginning and end of the ordering, and -0.0 should
// appear before 0.0. Also we want to have a stable sort, so if the keys are the
// same, we compare the index values.
template <typename KeyType>
bool LessThan(KeyType lhs, int64 lhs_index, KeyType rhs, int64 rhs_index) {
  bool lhs_is_negative = std::signbit(lhs);
  bool rhs_is_negative = std::signbit(rhs);
  // If the signs are different, we can just compare the signs.
  if (lhs_is_negative != rhs_is_negative) {
    return lhs_is_negative && !rhs_is_negative;
  }
  bool lhs_nan = std::isnan(lhs);
  bool rhs_nan = std::isnan(rhs);
  // Exactly one number is nan?
  if (lhs_nan != rhs_nan) {
    if (lhs_nan) {
      return lhs_is_negative;
    }
    return !rhs_is_negative;
  }
  if (lhs != rhs) {
    return lhs < rhs;
  }
  return lhs_index < rhs_index;
}

template <>
void KeyValueSort(std::pair<double, int64>* row_to_sort, int64 num_elements) {
  std::sort(row_to_sort, row_to_sort + num_elements,
            [](const std::pair<double, int64>& lhs,
               const std::pair<double, int64>& rhs) -> bool {
              return LessThan(lhs.first, lhs.second, rhs.first, rhs.second);
            });
}

template <>
void KeyValueSort(std::pair<float, int64>* row_to_sort, int64 num_elements) {
  std::sort(row_to_sort, row_to_sort + num_elements,
            [](const std::pair<float, int64>& lhs,
               const std::pair<float, int64>& rhs) -> bool {
              return LessThan(lhs.first, lhs.second, rhs.first, rhs.second);
            });
}

template <>
void KeyValueSort(std::pair<Eigen::half, int64>* row_to_sort,
                  int64 num_elements) {
  std::sort(row_to_sort, row_to_sort + num_elements,
            [](const std::pair<Eigen::half, int64>& lhs,
               const std::pair<Eigen::half, int64>& rhs) -> bool {
              return LessThan(
                  Eigen::half_impl::half_to_float(lhs.first), lhs.second,
                  Eigen::half_impl::half_to_float(rhs.first), rhs.second);
            });
}

template <typename KeyType>
void KeyValueSortImpl(KeyType* keys, int64 a, int64 b, int64 c, char** values,
                      int32 values_count,
                      int32* values_primitive_type_size_in_bytes) {
  // 'values' and 'values_primitive_type_size_in_bytes' are managed by the JIT
  // code, so msan can't tell they are initialized.
  TF_ANNOTATE_MEMORY_IS_INITIALIZED(values, values_count * sizeof(char*));
  TF_ANNOTATE_MEMORY_IS_INITIALIZED(values_primitive_type_size_in_bytes,
                                    values_count * sizeof(int32));

  // High-level idea of the iteration/sorting logic:
  // Conceptually we have a 3-dimensional shape [a, b, c]. b corresponds to the
  // dimension to sort, c is the product of the more minor dimensions (set to 1
  // if b is the most minor dimension), and a is the product of the more major
  // dimensions (set to 1 if b is the most major dimension). There are a * c
  // many rows that we need to sort. We iterate through these, calculate a
  // 'base_offset' value which points to the first element in that row, and add
  // i * c for accessing the 'i'-th element in that row.

  int64 sort_dimension_elements = b;
  int64 num_iteration_elements = a * c;
  int64 sort_dimension_offset = c;

  std::unique_ptr<std::pair<KeyType, int64>[]> row_to_sort(
      new std::pair<KeyType, int64>[sort_dimension_elements]);
  std::unique_ptr<std::string[]> reordered_values(
      new std::string[sort_dimension_elements]);
  for (int64 index = 0; index < num_iteration_elements; ++index) {
    // 'index' can be split into two values which index into the 'c' dimension
    // and the 'a' dimension, respectively. 'index' % 'c' is the index into the
    // 'c' dimension, 'index' / 'c' is the index into the 'a' dimension. When
    // calculating the base offset, we need to multiply the index into the 'a'
    // dimension with 'b' * 'c'.
    // 'index' / 'c' * 'c' * 'b' = ('index' - 'index' % 'c') * 'b'.
    int64 base_offset =
        index % sort_dimension_offset +
        (index - index % sort_dimension_offset) * sort_dimension_elements;
    // TODO(b/26783907): We could define a custom iterator class that references
    // all arrays. Then we could avoid the intermediate copy. However this
    // would become more complicated, and it is not clear if the benefit is high
    // enough.
    for (int64 i = 0; i < sort_dimension_elements; ++i) {
      row_to_sort[i] =
          std::make_pair(keys[base_offset + i * sort_dimension_offset], i);
    }
    KeyValueSort(row_to_sort.get(), sort_dimension_elements);
    for (int64 i = 0; i < sort_dimension_elements; ++i) {
      keys[base_offset + i * sort_dimension_offset] = row_to_sort[i].first;
    }

    // Reorder the values according to the order defined by the keys.
    for (int32 idx = 0; idx < values_count; ++idx) {
      for (int64 i = 0; i < sort_dimension_elements; ++i) {
        int64 memory_index =
            (base_offset + row_to_sort[i].second * sort_dimension_offset) *
            values_primitive_type_size_in_bytes[idx];

        reordered_values[i] =
            std::string(values[idx] + memory_index,
                        values_primitive_type_size_in_bytes[idx]);
      }
      for (int64 i = 0; i < sort_dimension_elements; ++i) {
        int64 memory_index = (base_offset + i * sort_dimension_offset) *
                             values_primitive_type_size_in_bytes[idx];
        memcpy(values[idx] + memory_index, reordered_values[i].c_str(),
               values_primitive_type_size_in_bytes[idx]);
      }
    }
  }
}
}  // namespace

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortPRED(
    bool* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortS8(
    int8* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortU8(
    uint8* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortS16(
    int16* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortU16(
    uint16* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortF16(
    Eigen::half* keys, int64 a, int64 b, int64 c, char** values,
    int32 values_count, int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortS32(
    int32* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortU32(
    uint32* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortF32(
    float* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortS64(
    int64* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortU64(
    uint64* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortF64(
    double* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}
<commit_msg>Improve the sort implementation for the CPU backend.<commit_after>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/compiler/xla/service/cpu/runtime_key_value_sort.h"

#include <algorithm>
#include <cmath>
#include <cstring>
#include <limits>
#include <memory>
#include <string>
#include <utility>

#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
#include "tensorflow/core/platform/dynamic_annotations.h"
#include "tensorflow/core/platform/macros.h"
#include "tensorflow/core/platform/types.h"

namespace {
using tensorflow::int16;
using tensorflow::int32;
using tensorflow::int64;
using tensorflow::int8;
using tensorflow::uint16;
using tensorflow::uint32;
using tensorflow::uint64;
using tensorflow::uint8;

template <typename KeyType>
void KeyValueSort(std::pair<KeyType, int64>* row_to_sort, int64 num_elements) {
  std::sort(row_to_sort, row_to_sort + num_elements);
}

// We would like a total order of floating point numbers so that the
// sort has a predictable behavior in the presence of NaNs. Rather
// than using floating point comparison, we use the following trick:
// If f is a float, and
// x = bit_cast<int32>(f);
// y = x < 0 ? 0x7FFFFFFF - x : x;
// then y is ordered as an int32 such that finite values have the
// obvious order, -0 is ordered before 0, and -NaN and NaN appear at
// the beginning and end of the ordering.
template <typename CastType, typename KeyType>
CastType Convert(KeyType value) {
  CastType casted_value;
  memcpy(&casted_value, &value, sizeof(CastType));
  if (casted_value < 0) {
    return std::numeric_limits<CastType>::max() - casted_value;
  }
  return casted_value;
}

template <typename CastType, typename KeyType>
bool LessThan(KeyType lhs, KeyType rhs) {
  return Convert<CastType>(lhs) < Convert<CastType>(rhs);
}

template <>
void KeyValueSort(std::pair<double, int64>* row_to_sort, int64 num_elements) {
  std::stable_sort(row_to_sort, row_to_sort + num_elements,
                   [](const std::pair<double, int64>& lhs,
                      const std::pair<double, int64>& rhs) -> bool {
                     return LessThan<int64>(lhs.first, rhs.first);
                   });
}

template <>
void KeyValueSort(std::pair<float, int64>* row_to_sort, int64 num_elements) {
  std::stable_sort(row_to_sort, row_to_sort + num_elements,
                   [](const std::pair<float, int64>& lhs,
                      const std::pair<float, int64>& rhs) -> bool {
                     return LessThan<int32>(lhs.first, rhs.first);
                   });
}

template <>
void KeyValueSort(std::pair<Eigen::half, int64>* row_to_sort,
                  int64 num_elements) {
  std::stable_sort(row_to_sort, row_to_sort + num_elements,
                   [](const std::pair<Eigen::half, int64>& lhs,
                      const std::pair<Eigen::half, int64>& rhs) -> bool {
                     return LessThan<int32>(
                         Eigen::half_impl::half_to_float(lhs.first),
                         Eigen::half_impl::half_to_float(rhs.first));
                   });
}

template <typename KeyType>
void KeyValueSortImpl(KeyType* keys, int64 a, int64 b, int64 c, char** values,
                      int32 values_count,
                      int32* values_primitive_type_size_in_bytes) {
  // 'values' and 'values_primitive_type_size_in_bytes' are managed by the JIT
  // code, so msan can't tell they are initialized.
  TF_ANNOTATE_MEMORY_IS_INITIALIZED(values, values_count * sizeof(char*));
  TF_ANNOTATE_MEMORY_IS_INITIALIZED(values_primitive_type_size_in_bytes,
                                    values_count * sizeof(int32));

  // High-level idea of the iteration/sorting logic:
  // Conceptually we have a 3-dimensional shape [a, b, c]. b corresponds to the
  // dimension to sort, c is the product of the more minor dimensions (set to 1
  // if b is the most minor dimension), and a is the product of the more major
  // dimensions (set to 1 if b is the most major dimension). There are a * c
  // many rows that we need to sort. We iterate through these, calculate a
  // 'base_offset' value which points to the first element in that row, and add
  // i * c for accessing the 'i'-th element in that row.

  int64 sort_dimension_elements = b;
  int64 num_iteration_elements = a * c;
  int64 sort_dimension_offset = c;

  std::unique_ptr<std::pair<KeyType, int64>[]> row_to_sort(
      new std::pair<KeyType, int64>[sort_dimension_elements]);
  std::unique_ptr<std::string[]> reordered_values(
      new std::string[sort_dimension_elements]);
  for (int64 index = 0; index < num_iteration_elements; ++index) {
    // 'index' can be split into two values which index into the 'c' dimension
    // and the 'a' dimension, respectively. 'index' % 'c' is the index into the
    // 'c' dimension, 'index' / 'c' is the index into the 'a' dimension. When
    // calculating the base offset, we need to multiply the index into the 'a'
    // dimension with 'b' * 'c'.
    // 'index' / 'c' * 'c' * 'b' = ('index' - 'index' % 'c') * 'b'.
    int64 base_offset =
        index % sort_dimension_offset +
        (index - index % sort_dimension_offset) * sort_dimension_elements;
    // TODO(b/26783907): We could define a custom iterator class that references
    // all arrays. Then we could avoid the intermediate copy. However this
    // would become more complicated, and it is not clear if the benefit is high
    // enough.
    for (int64 i = 0; i < sort_dimension_elements; ++i) {
      row_to_sort[i] =
          std::make_pair(keys[base_offset + i * sort_dimension_offset], i);
    }
    KeyValueSort(row_to_sort.get(), sort_dimension_elements);
    for (int64 i = 0; i < sort_dimension_elements; ++i) {
      keys[base_offset + i * sort_dimension_offset] = row_to_sort[i].first;
    }

    // Reorder the values according to the order defined by the keys.
    for (int32 idx = 0; idx < values_count; ++idx) {
      for (int64 i = 0; i < sort_dimension_elements; ++i) {
        int64 memory_index =
            (base_offset + row_to_sort[i].second * sort_dimension_offset) *
            values_primitive_type_size_in_bytes[idx];

        reordered_values[i] =
            std::string(values[idx] + memory_index,
                        values_primitive_type_size_in_bytes[idx]);
      }
      for (int64 i = 0; i < sort_dimension_elements; ++i) {
        int64 memory_index = (base_offset + i * sort_dimension_offset) *
                             values_primitive_type_size_in_bytes[idx];
        memcpy(values[idx] + memory_index, reordered_values[i].c_str(),
               values_primitive_type_size_in_bytes[idx]);
      }
    }
  }
}
}  // namespace

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortPRED(
    bool* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortS8(
    int8* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortU8(
    uint8* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortS16(
    int16* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortU16(
    uint16* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortF16(
    Eigen::half* keys, int64 a, int64 b, int64 c, char** values,
    int32 values_count, int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortS32(
    int32* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortU32(
    uint32* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortF32(
    float* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortS64(
    int64* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortU64(
    uint64* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}

TF_ATTRIBUTE_NO_SANITIZE_MEMORY void __xla_cpu_runtime_KeyValueSortF64(
    double* keys, int64 a, int64 b, int64 c, char** values, int32 values_count,
    int32* values_primitive_type_size_in_bytes) {
  KeyValueSortImpl(keys, a, b, c, values, values_count,
                   values_primitive_type_size_in_bytes);
}
<|endoftext|>


<commit_before>
/** \file phatbooks_database_connection.cpp
 *
 * \brief Source file pertaining to PhatbooksDatabaseConnection class.
 *
 * \author Matthew Harvey
 * \date 04 July 2012.
 *
 * Copyright (c) 2012, Matthew Harvey. All rights reserved.
 */

#include "account_impl.hpp"
#include "commodity_impl.hpp"
#include "entry_impl.hpp"
#include "draft_journal_impl.hpp"
#include "ordinary_journal_impl.hpp"
#include "repeater_impl.hpp"

#include "account.hpp"
#include "balance_cache.hpp"
#include "commodity.hpp"
#include "entry.hpp"
#include "draft_journal.hpp"
#include "journal.hpp"
#include "ordinary_journal.hpp"
#include "phatbooks_database_connection.hpp"
#include "phatbooks_exceptions.hpp"
#include "repeater.hpp"
#include <sqloxx/database_connection.hpp>
#include <sqloxx/database_transaction.hpp>
#include <sqloxx/identity_map.hpp>
#include <sqloxx/sqloxx_exceptions.hpp>
#include <sqloxx/sql_statement.hpp>
#include <sqlite3.h>
#include <stdexcept>
#include <boost/bimap.hpp>
#include <boost/filesystem.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/shared_ptr.hpp>
#include <jewel/decimal.hpp>
#include <cassert>
#include <iostream>
#include <list>
#include <stdexcept>
#include <string>

using boost::bimap;
using boost::numeric_cast;
using boost::shared_ptr;
using jewel::Decimal;
using sqloxx::DatabaseConnection;
using sqloxx::DatabaseTransaction;
using sqloxx::IdentityMap;
using sqloxx::SQLStatement;
using sqloxx::SQLiteException;
using std::endl;
using std::list;
using std::runtime_error;
using std::string;

namespace phatbooks
{

PhatbooksDatabaseConnection::PhatbooksDatabaseConnection():
	DatabaseConnection(),
	m_balance_cache(0),
	m_account_map(0),
	m_commodity_map(0),
	m_entry_map(0),
	m_ordinary_journal_map(0),
	m_draft_journal_map(0),
	m_repeater_map(0)
{
	typedef PhatbooksDatabaseConnection PDC;
	m_balance_cache = new BalanceCache(*this);
	m_account_map = new IdentityMap<AccountImpl, PDC>(*this);
	m_commodity_map = new IdentityMap<CommodityImpl, PDC>(*this);
	m_entry_map = new IdentityMap<EntryImpl, PDC>(*this);
	m_ordinary_journal_map = new IdentityMap<OrdinaryJournalImpl, PDC>(*this);
	m_draft_journal_map = new IdentityMap<DraftJournalImpl, PDC>(*this);
	m_repeater_map = new IdentityMap<RepeaterImpl, PDC>(*this);
}

PhatbooksDatabaseConnection::~PhatbooksDatabaseConnection()
{
	delete m_balance_cache;
	delete m_account_map;
	delete m_commodity_map;
	delete m_entry_map;
	delete m_ordinary_journal_map;
	delete m_draft_journal_map;
	delete m_repeater_map;
}

bool
PhatbooksDatabaseConnection::has_account_named(string const& p_name)
{
	SQLStatement statement
	(	*this,
		"select name from accounts where name = :p"
	);
	statement.bind(":p", p_name);
	return statement.step();
}

bool
PhatbooksDatabaseConnection::has_draft_journal_named(string const& p_name)
{
	SQLStatement statement
	(	*this,
		"select name from draft_journal_detail where name = :p"
	);
	statement.bind(":p", p_name);
	return statement.step();
}

bimap<Account::AccountType, string>
PhatbooksDatabaseConnection::account_types()
{
	typedef bimap<Account::AccountType, string> return_type;
	return_type ret;
	SQLStatement statement
	(	*this,
		"select account_type_id, name from account_types order "
		"by account_type_id"
	);
	while (statement.step())
	{
		Account::AccountType acctype = static_cast<Account::AccountType>
		(	statement.extract<Account::Id>(0)
		);
		string accname = statement.extract<string>(1);
		ret.insert(return_type::value_type(acctype, accname));
	}
	return ret;
}

bool
PhatbooksDatabaseConnection::has_commodity_with_abbreviation
(	string const& p_abbreviation
)
{
	SQLStatement statement
	(	*this,
		"select abbreviation from commodities where abbreviation = :p"
	);
	statement.bind(":p", p_abbreviation);
	return statement.step();
}

bool
PhatbooksDatabaseConnection::has_commodity_named(string const& p_name)
{
	SQLStatement statement
	(	*this,
		"select name from commodities where name = :p"
	);
	statement.bind(":p", p_name);
	return statement.step();
}

void
PhatbooksDatabaseConnection::setup()
{
	if (setup_has_occurred())
	{
		return;
	}
	assert (!setup_has_occurred());
	DatabaseTransaction transaction(*this);
	setup_boolean_table();
	Commodity::setup_tables(*this);
	Account::setup_tables(*this);
	Journal::setup_tables(*this);
	DraftJournal::setup_tables(*this);
	OrdinaryJournal::setup_tables(*this);
	Repeater::setup_tables(*this);
	Entry::setup_tables(*this);
	mark_setup_as_having_occurred();
	transaction.commit();
	assert (setup_has_occurred());
	return;
}

void
PhatbooksDatabaseConnection::set_caching_level(unsigned int level)
{
	switch (level)
	{
	case 0: case 1: case 2: case 3: case 4:
		m_commodity_map->disable_caching();
		m_account_map->disable_caching();
		m_repeater_map->disable_caching();
		m_draft_journal_map->disable_caching();
		m_ordinary_journal_map->disable_caching();
		m_entry_map->disable_caching();
		break;
	case 5: case 6: case 7: case 8: case 9:
		m_commodity_map->enable_caching();
		m_account_map->enable_caching();
		m_repeater_map->disable_caching();
		m_draft_journal_map->disable_caching();
		m_ordinary_journal_map->disable_caching();
		m_entry_map->disable_caching();
		break;
	case 10: default:
		assert (level > 0);
		m_commodity_map->enable_caching();
		m_account_map->enable_caching();
		m_repeater_map->enable_caching();
		m_draft_journal_map->enable_caching();
		m_ordinary_journal_map->enable_caching();
		m_entry_map->enable_caching();
		break;
	}
	return;
}

namespace
{
	string const setup_flag = "setup_flag_996149162";
}

void
PhatbooksDatabaseConnection::mark_setup_as_having_occurred()
{
	execute_sql("create table " + setup_flag + "(dummy_column);");
	return;
}

bool
PhatbooksDatabaseConnection::setup_has_occurred()
{
	try
	{
		execute_sql("select * from " + setup_flag);
		return true;
	}
	catch (SQLiteException&)
	{
		return false;
	}
}

// BalanceCacheAttorney

typedef
	PhatbooksDatabaseConnection::BalanceCacheAttorney
	BalanceCacheAttorney;

void
BalanceCacheAttorney::mark_as_stale
(	PhatbooksDatabaseConnection const& p_database_connection
)
{
	p_database_connection.m_balance_cache->mark_as_stale();
	return;
}

void
BalanceCacheAttorney::mark_as_stale
(	PhatbooksDatabaseConnection const& p_database_connection,
	AccountImpl::Id p_account_id
)
{
	p_database_connection.m_balance_cache->mark_as_stale
	(	p_account_id
	);
	return;
}

Decimal
BalanceCacheAttorney::technical_balance
(	PhatbooksDatabaseConnection const& p_database_connection,
	AccountImpl::Id p_account_id
)
{
	return p_database_connection.m_balance_cache->technical_balance
	(	p_account_id
	);
}

template <>
sqloxx::IdentityMap<AccountImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<AccountImpl>()
{
	return *m_account_map;
}

template <>
sqloxx::IdentityMap<EntryImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<EntryImpl>()
{
	return *m_entry_map;
}

template <>
sqloxx::IdentityMap<CommodityImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<CommodityImpl>()
{
	return *m_commodity_map;
}

template <>
sqloxx::IdentityMap<OrdinaryJournalImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<OrdinaryJournalImpl>()
{
	return *m_ordinary_journal_map;
}

template <>
sqloxx::IdentityMap<phatbooks::DraftJournalImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<DraftJournalImpl>()
{
	return *m_draft_journal_map;
}

template <>
sqloxx::IdentityMap<phatbooks::RepeaterImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<RepeaterImpl>()
{
	return *m_repeater_map;
}

}  // namespace phatbooks

<commit_msg>Added a TODO to phatbooks_database_connection.cpp.<commit_after>
/** \file phatbooks_database_connection.cpp
 *
 * \brief Source file pertaining to PhatbooksDatabaseConnection class.
 *
 * \author Matthew Harvey
 * \date 04 July 2012.
 *
 * Copyright (c) 2012, Matthew Harvey. All rights reserved.
 */

#include "account_impl.hpp"
#include "commodity_impl.hpp"
#include "entry_impl.hpp"
#include "draft_journal_impl.hpp"
#include "ordinary_journal_impl.hpp"
#include "repeater_impl.hpp"

#include "account.hpp"
#include "balance_cache.hpp"
#include "commodity.hpp"
#include "entry.hpp"
#include "draft_journal.hpp"
#include "journal.hpp"
#include "ordinary_journal.hpp"
#include "phatbooks_database_connection.hpp"
#include "phatbooks_exceptions.hpp"
#include "repeater.hpp"
#include <sqloxx/database_connection.hpp>
#include <sqloxx/database_transaction.hpp>
#include <sqloxx/identity_map.hpp>
#include <sqloxx/sqloxx_exceptions.hpp>
#include <sqloxx/sql_statement.hpp>
#include <sqlite3.h>
#include <stdexcept>
#include <boost/bimap.hpp>
#include <boost/filesystem.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/shared_ptr.hpp>
#include <jewel/decimal.hpp>
#include <cassert>
#include <iostream>
#include <list>
#include <stdexcept>
#include <string>

using boost::bimap;
using boost::numeric_cast;
using boost::shared_ptr;
using jewel::Decimal;
using sqloxx::DatabaseConnection;
using sqloxx::DatabaseTransaction;
using sqloxx::IdentityMap;
using sqloxx::SQLStatement;
using sqloxx::SQLiteException;
using std::endl;
using std::list;
using std::runtime_error;
using std::string;

namespace phatbooks
{

PhatbooksDatabaseConnection::PhatbooksDatabaseConnection():
	DatabaseConnection(),
	m_balance_cache(0),
	m_account_map(0),
	m_commodity_map(0),
	m_entry_map(0),
	m_ordinary_journal_map(0),
	m_draft_journal_map(0),
	m_repeater_map(0)
{
	typedef PhatbooksDatabaseConnection PDC;
	m_balance_cache = new BalanceCache(*this);
	m_account_map = new IdentityMap<AccountImpl, PDC>(*this);
	m_commodity_map = new IdentityMap<CommodityImpl, PDC>(*this);
	m_entry_map = new IdentityMap<EntryImpl, PDC>(*this);
	m_ordinary_journal_map = new IdentityMap<OrdinaryJournalImpl, PDC>(*this);
	m_draft_journal_map = new IdentityMap<DraftJournalImpl, PDC>(*this);
	m_repeater_map = new IdentityMap<RepeaterImpl, PDC>(*this);
}

PhatbooksDatabaseConnection::~PhatbooksDatabaseConnection()
{
	delete m_balance_cache;
	delete m_account_map;
	delete m_commodity_map;
	delete m_entry_map;
	delete m_ordinary_journal_map;
	delete m_draft_journal_map;
	delete m_repeater_map;
}

bool
PhatbooksDatabaseConnection::has_account_named(string const& p_name)
{
	SQLStatement statement
	(	*this,
		"select name from accounts where name = :p"
	);
	statement.bind(":p", p_name);
	return statement.step();
}

bool
PhatbooksDatabaseConnection::has_draft_journal_named(string const& p_name)
{
	SQLStatement statement
	(	*this,
		"select name from draft_journal_detail where name = :p"
	);
	statement.bind(":p", p_name);
	return statement.step();
}

// TODO This is clunky. The account type names should be stored in
// memory from the outset, as part of the application code, and not
// stored in the database at all. They should be dealt with in the
// same way as IntervalType.
bimap<Account::AccountType, string>
PhatbooksDatabaseConnection::account_types()
{
	typedef bimap<Account::AccountType, string> return_type;
	return_type ret;
	SQLStatement statement
	(	*this,
		"select account_type_id, name from account_types order "
		"by account_type_id"
	);
	while (statement.step())
	{
		Account::AccountType acctype = static_cast<Account::AccountType>
		(	statement.extract<Account::Id>(0)
		);
		string accname = statement.extract<string>(1);
		ret.insert(return_type::value_type(acctype, accname));
	}
	return ret;
}

bool
PhatbooksDatabaseConnection::has_commodity_with_abbreviation
(	string const& p_abbreviation
)
{
	SQLStatement statement
	(	*this,
		"select abbreviation from commodities where abbreviation = :p"
	);
	statement.bind(":p", p_abbreviation);
	return statement.step();
}

bool
PhatbooksDatabaseConnection::has_commodity_named(string const& p_name)
{
	SQLStatement statement
	(	*this,
		"select name from commodities where name = :p"
	);
	statement.bind(":p", p_name);
	return statement.step();
}

void
PhatbooksDatabaseConnection::setup()
{
	if (setup_has_occurred())
	{
		return;
	}
	assert (!setup_has_occurred());
	DatabaseTransaction transaction(*this);
	setup_boolean_table();
	Commodity::setup_tables(*this);
	Account::setup_tables(*this);
	Journal::setup_tables(*this);
	DraftJournal::setup_tables(*this);
	OrdinaryJournal::setup_tables(*this);
	Repeater::setup_tables(*this);
	Entry::setup_tables(*this);
	mark_setup_as_having_occurred();
	transaction.commit();
	assert (setup_has_occurred());
	return;
}

void
PhatbooksDatabaseConnection::set_caching_level(unsigned int level)
{
	switch (level)
	{
	case 0: case 1: case 2: case 3: case 4:
		m_commodity_map->disable_caching();
		m_account_map->disable_caching();
		m_repeater_map->disable_caching();
		m_draft_journal_map->disable_caching();
		m_ordinary_journal_map->disable_caching();
		m_entry_map->disable_caching();
		break;
	case 5: case 6: case 7: case 8: case 9:
		m_commodity_map->enable_caching();
		m_account_map->enable_caching();
		m_repeater_map->disable_caching();
		m_draft_journal_map->disable_caching();
		m_ordinary_journal_map->disable_caching();
		m_entry_map->disable_caching();
		break;
	case 10: default:
		assert (level > 0);
		m_commodity_map->enable_caching();
		m_account_map->enable_caching();
		m_repeater_map->enable_caching();
		m_draft_journal_map->enable_caching();
		m_ordinary_journal_map->enable_caching();
		m_entry_map->enable_caching();
		break;
	}
	return;
}

namespace
{
	string const setup_flag = "setup_flag_996149162";
}

void
PhatbooksDatabaseConnection::mark_setup_as_having_occurred()
{
	execute_sql("create table " + setup_flag + "(dummy_column);");
	return;
}

bool
PhatbooksDatabaseConnection::setup_has_occurred()
{
	try
	{
		execute_sql("select * from " + setup_flag);
		return true;
	}
	catch (SQLiteException&)
	{
		return false;
	}
}

// BalanceCacheAttorney

typedef
	PhatbooksDatabaseConnection::BalanceCacheAttorney
	BalanceCacheAttorney;

void
BalanceCacheAttorney::mark_as_stale
(	PhatbooksDatabaseConnection const& p_database_connection
)
{
	p_database_connection.m_balance_cache->mark_as_stale();
	return;
}

void
BalanceCacheAttorney::mark_as_stale
(	PhatbooksDatabaseConnection const& p_database_connection,
	AccountImpl::Id p_account_id
)
{
	p_database_connection.m_balance_cache->mark_as_stale
	(	p_account_id
	);
	return;
}

Decimal
BalanceCacheAttorney::technical_balance
(	PhatbooksDatabaseConnection const& p_database_connection,
	AccountImpl::Id p_account_id
)
{
	return p_database_connection.m_balance_cache->technical_balance
	(	p_account_id
	);
}

template <>
sqloxx::IdentityMap<AccountImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<AccountImpl>()
{
	return *m_account_map;
}

template <>
sqloxx::IdentityMap<EntryImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<EntryImpl>()
{
	return *m_entry_map;
}

template <>
sqloxx::IdentityMap<CommodityImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<CommodityImpl>()
{
	return *m_commodity_map;
}

template <>
sqloxx::IdentityMap<OrdinaryJournalImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<OrdinaryJournalImpl>()
{
	return *m_ordinary_journal_map;
}

template <>
sqloxx::IdentityMap<phatbooks::DraftJournalImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<DraftJournalImpl>()
{
	return *m_draft_journal_map;
}

template <>
sqloxx::IdentityMap<phatbooks::RepeaterImpl, PhatbooksDatabaseConnection>&
PhatbooksDatabaseConnection::identity_map<RepeaterImpl>()
{
	return *m_repeater_map;
}

}  // namespace phatbooks

<|endoftext|>


<commit_before>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//  header and chunks writing
//
// Author: Skal (pascal.massimino@gmail.com)

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#include "sjpegi.h"

using namespace sjpeg;

namespace sjpeg {

////////////////////////////////////////////////////////////////////////////////
// Headers
//
// NOTE(skal): all chunks start with a startcode '0xff??' (0xffd8 e.g),
// followed by the size of the payload *not counting the startcode*!
// That's why you often find these 'Reserve(data_size + 2)' below, the '+2'
// accounting for the 0xff?? startcode size.

void Encoder::WriteAPP0() {  // SOI + APP0
  const uint8_t kHeader0[] = {
    0xff, 0xd8,                     // SOI
    0xff, 0xe0, 0x00, 0x10,         // APP0
    0x4a, 0x46, 0x49, 0x46, 0x00,   // 'JFIF'
    0x01, 0x01,                     // v1.01
    0x00, 0x00, 0x01, 0x00, 0x01,   // aspect ratio = 1:1
    0x00, 0x00                      // thumbnail width/height
  };
  bw_.Reserve(sizeof(kHeader0));
  bw_.PutBytes(kHeader0, sizeof(kHeader0));
}

bool Encoder::WriteAPPMarkers(const std::string& data) {
  if (data.size() == 0) return true;
  const size_t data_size = data.size();
  bw_.Reserve(data_size);
  bw_.PutBytes(reinterpret_cast<const uint8_t*>(data.data()), data.size());
  return true;
}

bool Encoder::WriteEXIF(const std::string& data) {
  if (data.size() == 0) return true;
  const uint8_t kEXIF[] = "Exif\0";
  const size_t kEXIF_len = 6;  // includes the \0's
  const size_t data_size = data.size() + kEXIF_len + 2;
  if (data_size > 0xffff) return false;
  bw_.Reserve(data_size);
  bw_.PutByte(0xff);
  bw_.PutByte(0xe1);
  bw_.PutByte((data_size >> 8) & 0xff);
  bw_.PutByte((data_size >> 0) & 0xff);
  bw_.PutBytes(kEXIF, kEXIF_len);
  bw_.PutBytes(reinterpret_cast<const uint8_t*>(data.data()), data.size());
  return true;
}

bool Encoder::WriteICCP(const std::string& data) {
  if (data.size() == 0) return true;
  size_t data_size = data.size();
  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data.data());
  const uint8_t kICCP[] = "ICC_PROFILE";
  const size_t kICCP_len = 12;  // includes the \0
  const size_t chunk_size_max = 0xffff - kICCP_len - 4;
  size_t max_chunk = (data_size + chunk_size_max - 1) / chunk_size_max;
  if (max_chunk >= 256) return false;
  size_t seq = 1;
  while (data_size > 0) {
    size_t size = data_size;
    if (size > chunk_size_max) size = chunk_size_max;
    bw_.Reserve(size + kICCP_len + 4 + 2);
    bw_.PutByte(0xff);
    bw_.PutByte(0xe2);
    bw_.PutByte(((size + kICCP_len + 4) >> 8) & 0xff);
    bw_.PutByte(((size + kICCP_len + 4) >> 0) & 0xff);
    bw_.PutBytes(kICCP, kICCP_len);
    bw_.PutByte(seq & 0xff);
    bw_.PutByte(max_chunk & 0xff);
    bw_.PutBytes(ptr, size);
    ptr += size;
    data_size -= size;
    seq += 1;
  }
  return true;
}

bool Encoder::WriteXMP(const std::string& data) {
  if (data.size() == 0) return true;
  const uint8_t kXMP[] = "http://ns.adobe.com/xap/1.0/";
  const size_t kXMP_size = 29;
  const size_t data_size = 2 + data.size() + kXMP_size;
  if (data_size > 0xffff) return false;  // error
  bw_.Reserve(data_size + 2);
  bw_.PutByte(0xff);
  bw_.PutByte(0xe1);
  bw_.PutByte((data_size >> 8) & 0xff);
  bw_.PutByte((data_size >> 0) & 0xff);
  bw_.PutBytes(kXMP, kXMP_size);
  bw_.PutBytes(reinterpret_cast<const uint8_t*>(data.data()), data.size());
  return true;
}

void Encoder::WriteDQT() {
  const int data_size = 2 * 65 + 2;
  const uint8_t kDQTHeader[] = { 0xff, 0xdb, 0x00, (uint8_t)data_size };
  bw_.Reserve(data_size + 2);
  bw_.PutBytes(kDQTHeader, sizeof(kDQTHeader));
  for (int n = 0; n <= 1; ++n) {
    bw_.PutByte(n);
    const uint8_t* quant = quants_[n].quant_;
    for (int i = 0; i < 64; ++i) {
      bw_.PutByte(quant[kZigzag[i]]);
    }
  }
}

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

#define DATA_16b(X) ((uint8_t)((X) >> 8)), ((uint8_t)((X) & 0xff))

void Encoder::WriteSOF() {   // SOF
  const int data_size = 8 + 3 * nb_comps_;
  assert(data_size <= 255);
  const uint8_t kHeader[] = {
    0xff, 0xc0, DATA_16b(data_size),         // SOF0 marker, size
    0x08,                                    // 8bits/components
    DATA_16b(H_), DATA_16b(W_),              // height, width
    (uint8_t)nb_comps_                       // number of components
  };
  bw_.Reserve(data_size + 2);
  bw_.PutBytes(kHeader, sizeof(kHeader));
  for (int c = 0; c < nb_comps_; ++c) {
    bw_.PutByte(c + 1);
    bw_.PutByte(block_dims_[c]);
    bw_.PutByte(quant_idx_[c]);
  }
}

void Encoder::WriteDHT() {
  InitCodes(false);
  const int nb_tables = (nb_comps_ == 1 ? 1 : 2);
  for (int c = 0; c < nb_tables; ++c) {   // luma, chroma
    for (int type = 0; type <= 1; ++type) {               // dc, ac
      const HuffmanTable* const h = Huffman_tables_[type * 2 + c];
      const int data_size = 3 + 16 + h->nb_syms_;
      assert(data_size <= 255);
      bw_.Reserve(data_size + 2);
      bw_.PutByte(0xff);
      bw_.PutByte(0xc4);
      bw_.PutByte(0x00 /*data_size >> 8*/);
      bw_.PutByte(data_size);
      bw_.PutByte((type << 4) | c);
      bw_.PutBytes(h->bits_, 16);
      bw_.PutBytes(h->syms_, h->nb_syms_);
    }
  }
}

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

void Encoder::WriteSOS() {   // SOS
  const int data_size = 6 + nb_comps_ * 2;
  assert(data_size <= 255);
  const uint8_t kHeader[] = {
      0xff, 0xda, DATA_16b(data_size), (uint8_t)nb_comps_
  };
  bw_.Reserve(data_size + 2);
  bw_.PutBytes(kHeader, sizeof(kHeader));
  for (int c = 0; c < nb_comps_; ++c) {
    bw_.PutByte(c + 1);
    bw_.PutByte(quant_idx_[c] * 0x11);
  }
  bw_.PutByte(0x00);        // Ss
  bw_.PutByte(0x3f);        // Se
  bw_.PutByte(0x00);        // Ah/Al
}

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

void Encoder::WriteEOI() {   // EOI
  bw_.Flush();
  // append EOI
  bw_.Reserve(2);
  bw_.PutByte(0xff);
  bw_.PutByte(0xd9);
}

}    // namespace sjpeg
<commit_msg>fix bug in data_size calculation for EXIF chunk<commit_after>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//  header and chunks writing
//
// Author: Skal (pascal.massimino@gmail.com)

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#include "sjpegi.h"

using namespace sjpeg;

namespace sjpeg {

////////////////////////////////////////////////////////////////////////////////
// Headers
//
// NOTE(skal): all chunks start with a startcode '0xff??' (0xffd8 e.g),
// followed by the size of the payload *not counting the startcode*!
// That's why you often find these 'Reserve(data_size + 2)' below, the '+2'
// accounting for the 0xff?? startcode size.

void Encoder::WriteAPP0() {  // SOI + APP0
  const uint8_t kHeader0[] = {
    0xff, 0xd8,                     // SOI
    0xff, 0xe0, 0x00, 0x10,         // APP0
    0x4a, 0x46, 0x49, 0x46, 0x00,   // 'JFIF'
    0x01, 0x01,                     // v1.01
    0x00, 0x00, 0x01, 0x00, 0x01,   // aspect ratio = 1:1
    0x00, 0x00                      // thumbnail width/height
  };
  bw_.Reserve(sizeof(kHeader0));
  bw_.PutBytes(kHeader0, sizeof(kHeader0));
}

bool Encoder::WriteAPPMarkers(const std::string& data) {
  if (data.size() == 0) return true;
  const size_t data_size = data.size();
  bw_.Reserve(data_size);
  bw_.PutBytes(reinterpret_cast<const uint8_t*>(data.data()), data.size());
  return true;
}

bool Encoder::WriteEXIF(const std::string& data) {
  if (data.size() == 0) return true;
  const uint8_t kEXIF[] = "Exif\0";
  const size_t kEXIF_len = 6;  // includes the \0's
  const size_t data_size = data.size() + kEXIF_len + 2;
  if (data_size > 0xffff) return false;
  bw_.Reserve(data_size + 2);
  bw_.PutByte(0xff);
  bw_.PutByte(0xe1);
  bw_.PutByte((data_size >> 8) & 0xff);
  bw_.PutByte((data_size >> 0) & 0xff);
  bw_.PutBytes(kEXIF, kEXIF_len);
  bw_.PutBytes(reinterpret_cast<const uint8_t*>(data.data()), data.size());
  return true;
}

bool Encoder::WriteICCP(const std::string& data) {
  if (data.size() == 0) return true;
  size_t data_size = data.size();
  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data.data());
  const uint8_t kICCP[] = "ICC_PROFILE";
  const size_t kICCP_len = 12;  // includes the \0
  const size_t chunk_size_max = 0xffff - kICCP_len - 4;
  size_t max_chunk = (data_size + chunk_size_max - 1) / chunk_size_max;
  if (max_chunk >= 256) return false;
  size_t seq = 1;
  while (data_size > 0) {
    size_t size = data_size;
    if (size > chunk_size_max) size = chunk_size_max;
    bw_.Reserve(size + kICCP_len + 4 + 2);
    bw_.PutByte(0xff);
    bw_.PutByte(0xe2);
    bw_.PutByte(((size + kICCP_len + 4) >> 8) & 0xff);
    bw_.PutByte(((size + kICCP_len + 4) >> 0) & 0xff);
    bw_.PutBytes(kICCP, kICCP_len);
    bw_.PutByte(seq & 0xff);
    bw_.PutByte(max_chunk & 0xff);
    bw_.PutBytes(ptr, size);
    ptr += size;
    data_size -= size;
    seq += 1;
  }
  return true;
}

bool Encoder::WriteXMP(const std::string& data) {
  if (data.size() == 0) return true;
  const uint8_t kXMP[] = "http://ns.adobe.com/xap/1.0/";
  const size_t kXMP_size = 29;
  const size_t data_size = 2 + data.size() + kXMP_size;
  if (data_size > 0xffff) return false;  // error
  bw_.Reserve(data_size + 2);
  bw_.PutByte(0xff);
  bw_.PutByte(0xe1);
  bw_.PutByte((data_size >> 8) & 0xff);
  bw_.PutByte((data_size >> 0) & 0xff);
  bw_.PutBytes(kXMP, kXMP_size);
  bw_.PutBytes(reinterpret_cast<const uint8_t*>(data.data()), data.size());
  return true;
}

void Encoder::WriteDQT() {
  const size_t data_size = 2 * 65 + 2;
  const uint8_t kDQTHeader[] = { 0xff, 0xdb, 0x00, (uint8_t)data_size };
  bw_.Reserve(data_size + 2);
  bw_.PutBytes(kDQTHeader, sizeof(kDQTHeader));
  for (int n = 0; n <= 1; ++n) {
    bw_.PutByte(n);
    const uint8_t* quant = quants_[n].quant_;
    for (int i = 0; i < 64; ++i) {
      bw_.PutByte(quant[kZigzag[i]]);
    }
  }
}

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

#define DATA_16b(X) ((uint8_t)((X) >> 8)), ((uint8_t)((X) & 0xff))

void Encoder::WriteSOF() {   // SOF
  const size_t data_size = 3 * nb_comps_ + 8;
  assert(data_size <= 255);
  const uint8_t kHeader[] = {
    0xff, 0xc0, DATA_16b(data_size),         // SOF0 marker, size
    0x08,                                    // 8bits/components
    DATA_16b(H_), DATA_16b(W_),              // height, width
    (uint8_t)nb_comps_                       // number of components
  };
  bw_.Reserve(data_size + 2);
  bw_.PutBytes(kHeader, sizeof(kHeader));
  for (int c = 0; c < nb_comps_; ++c) {
    bw_.PutByte(c + 1);
    bw_.PutByte(block_dims_[c]);
    bw_.PutByte(quant_idx_[c]);
  }
}

void Encoder::WriteDHT() {
  InitCodes(false);
  const int nb_tables = (nb_comps_ == 1 ? 1 : 2);
  for (int c = 0; c < nb_tables; ++c) {   // luma, chroma
    for (int type = 0; type <= 1; ++type) {               // dc, ac
      const HuffmanTable* const h = Huffman_tables_[type * 2 + c];
      const size_t data_size = 3 + 16 + h->nb_syms_;
      assert(data_size <= 255);
      bw_.Reserve(data_size + 2);
      bw_.PutByte(0xff);
      bw_.PutByte(0xc4);
      bw_.PutByte(0x00 /*data_size >> 8*/);
      bw_.PutByte(data_size);
      bw_.PutByte((type << 4) | c);
      bw_.PutBytes(h->bits_, 16);
      bw_.PutBytes(h->syms_, h->nb_syms_);
    }
  }
}

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

void Encoder::WriteSOS() {   // SOS
  const size_t data_size = 3 + nb_comps_ * 2 + 3;
  assert(data_size <= 255);
  const uint8_t kHeader[] = {
      0xff, 0xda, DATA_16b(data_size), (uint8_t)nb_comps_
  };
  bw_.Reserve(data_size + 2);
  bw_.PutBytes(kHeader, sizeof(kHeader));
  for (int c = 0; c < nb_comps_; ++c) {
    bw_.PutByte(c + 1);
    bw_.PutByte(quant_idx_[c] * 0x11);
  }
  bw_.PutByte(0x00);        // Ss
  bw_.PutByte(0x3f);        // Se
  bw_.PutByte(0x00);        // Ah/Al
}

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

void Encoder::WriteEOI() {   // EOI
  bw_.Flush();
  // append EOI
  bw_.Reserve(2);
  bw_.PutByte(0xff);
  bw_.PutByte(0xd9);
}

}    // namespace sjpeg
<|endoftext|>


<commit_before>#include <stdio.h>

typedef unsigned long int  UInt32;
typedef signed long int    SInt32;
typedef unsigned short int UInt16;
typedef signed short int   SInt16;
typedef unsigned char      UInt8;
typedef signed char        SInt8;
typedef int                Bool;

static const Bool true = 1;
static const Bool false = 0;

int main(int argc, char* argv[])
{
    if (argc < 2) {
        printf("Syntax: %s <filename>\n", argv[0]);
        exit(1);
    }
    FILE* in = fopen(argv[1], "rb");
    fseek(in, 0, SEEK_END);
    UInt32 s = ftell(in);
    fseek(in, 0, SEEK_SET);
    UInt8* mod = 0;
    if (s <= 0xffffL)
        mod = (UInt8*)malloc((UInt16)s);
    if (mod == 0) {
        printf("File too large - must be under %u bytes\n", coreleft());
        exit(1);
    }
    fread((void*)mod, (UInt16)s, 1, in);
    fclose(in);
    // TODO: Compute offset of start of samples
    // TODO: Compute segment for player/sample data

}

<commit_msg>MOD player<commit_after>#include <stdio.h>

typedef unsigned long int  UInt32;
typedef signed long int    SInt32;
typedef unsigned short int UInt16;
typedef signed short int   SInt16;
typedef unsigned char      UInt8;
typedef signed char        SInt8;
typedef int                Bool;

static const Bool true = 1;
static const Bool false = 0;

int main(int argc, char* argv[])
{
    if (argc < 2) {
        printf("Syntax: %s <filename>\n", argv[0]);
        exit(1);
    }
    FILE* in = fopen(argv[1], "rb");
    fseek(in, 0, SEEK_END);
    UInt32 s = ftell(in);
    fseek(in, 0, SEEK_SET);
    UInt8* mod = 0;
    if (s <= 0xffffL)
        mod = (UInt8*)malloc((UInt16)s);
    if (mod == 0) {
        printf("File too large - must be under %u bytes\n", coreleft());
        exit(1);
    }
    fread((void*)mod, (UInt16)s, 1, in);
    fclose(in);
    UInt8 positions = mod[950];
    UInt8 highestPosition = 0;
    for (UInt8 position = 0; position < positions; ++position) {
        UInt8 pattern = mod[952+position];
        if (pattern > highestPosition)
            highestPosition = pattern;
    }
    UInt8 samplesStart = 1084 + (highestPosition + 1)*1024;
    UInt8 far* p = &samplesStart;
    UInt16 ss = FP_SEG(p);
    UInt16 playerSegment = ss + 0x1000;

}

<|endoftext|>