<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  Copyright (c) 2012-, Open Perception, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 *
 */
#include <pcl/io/pcd_grabber.h>
#include <pcl/console/parse.h>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <pcl/console/print.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/visualization/image_viewer.h>

using pcl::console::print_error;
using pcl::console::print_info;
using pcl::console::print_value;

boost::mutex mutex_;
boost::shared_ptr<pcl::PCDGrabber<pcl::PointXYZRGBA> > grabber;
pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr cloud_;

void
printHelp (int, char **argv)
{
  //print_error ("Syntax is: %s <file_name 1..N>.pcd <options>\n", argv[0]);
  print_error ("Syntax is: %s <options>\n", argv[0]);
  print_info ("  where options are:\n");
  print_info ("                     -file file_name          = PCD file to be read from\n");
  print_info ("                     -dir directory_path      = directory path to PCD file(s) to be read from\n");
  print_info ("                     -fps frequency           = frames per second\n");
  print_info ("                     -repeat                  = optional parameter that tells wheter the PCD file(s) should be \"grabbed\" in a endless loop.\n");
  print_info ("\n");
  print_info ("                     -cam (*)                 = use given camera settings as initial view\n");
  print_info (stderr, " (*) [Clipping Range / Focal Point / Position / ViewUp / Distance / Window Size / Window Pos] or use a <filename.cam> that contains the same information.\n");
}

// Create the PCLVisualizer object
boost::shared_ptr<pcl::visualization::PCLVisualizer> cloud_viewer;
#if !((VTK_MAJOR_VERSION == 5)&&(VTK_MINOR_VERSION <= 4))
boost::shared_ptr<pcl::visualization::ImageViewer> img_viewer;
#endif

std::vector<double> fcolor_r, fcolor_b, fcolor_g;
bool fcolorparam = false;

struct EventHelper
{
  void
  cloud_cb (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr & cloud)
  {
    if (mutex_.try_lock ())
    {
      cloud_ = cloud;
      mutex_.unlock ();
    }
  }
};

void
keyboard_callback (const pcl::visualization::KeyboardEvent& event, void*)
{
  /// If SPACE is pressed, trigger new cloud callback (only works if framerate is set to 0)
  if (event.getKeyCode() == ' ' && grabber)
    grabber->trigger ();
}

void
mouse_callback (const pcl::visualization::MouseEvent& mouse_event, void* cookie)
{
  std::string* message = static_cast<std::string*> (cookie);
  if (mouse_event.getType() == pcl::visualization::MouseEvent::MouseButtonPress && mouse_event.getButton() == pcl::visualization::MouseEvent::LeftButton)
  {
    cout << (*message) << " :: " << mouse_event.getX () << " , " << mouse_event.getY () << endl;
  }
}

/* ---[ */
int
main (int argc, char** argv)
{
  srand (unsigned (time (0)));

  if (argc > 1)
  {
    for (int i = 1; i < argc; i++)
    {
      if (std::string (argv[i]) == "-h")
      {
        printHelp (argc, argv);
        return (-1);
      }
    }
  }

  // Command line parsing
  double bcolor[3] = {0, 0, 0};
  pcl::console::parse_3x_arguments (argc, argv, "-bc", bcolor[0], bcolor[1], bcolor[2]);

  fcolorparam = pcl::console::parse_multiple_3x_arguments (argc, argv, "-fc", fcolor_r, fcolor_g, fcolor_b);

  int psize = 0;
  pcl::console::parse_argument (argc, argv, "-ps", psize);

  double opaque;
  pcl::console::parse_argument (argc, argv, "-opaque", opaque);

  cloud_viewer.reset (new pcl::visualization::PCLVisualizer (argc, argv, "PCD viewer"));

#if !((VTK_MAJOR_VERSION == 5)&&(VTK_MINOR_VERSION <= 4))
  img_viewer.reset (new pcl::visualization::ImageViewer ("OpenNI Viewer"));
#endif

  //  // Change the cloud rendered point size
  //  if (psize > 0)
  //    p->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, psize, "OpenNICloud");
  //
  //  // Change the cloud rendered opacity
  //  if (opaque >= 0)
  //    p->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_OPACITY, opaque, "OpenNICloud");

  cloud_viewer->setBackgroundColor (bcolor[0], bcolor[1], bcolor[2]);

  // Read axes settings
  double axes = 0.0;
  pcl::console::parse_argument (argc, argv, "-ax", axes);
  if (axes != 0.0 && cloud_viewer)
  {
    float ax_x = 0.0, ax_y = 0.0, ax_z = 0.0;
    pcl::console::parse_3x_arguments (argc, argv, "-ax_pos", ax_x, ax_y, ax_z, false);
    // Draw XYZ axes if command-line enabled
    cloud_viewer->addCoordinateSystem (axes, ax_x, ax_y, ax_z);
  }

  float frames_per_second = 0; // 0 means only if triggered!
  pcl::console::parse (argc, argv, "-fps", frames_per_second);
  if (frames_per_second < 0)
    frames_per_second = 0.0;

  bool repeat = (pcl::console::find_argument (argc, argv, "-repeat") != -1);

  std::cout << "fps: " << frames_per_second << " , repeat: " << repeat << std::endl;
  std::string path = "";
  pcl::console::parse_argument (argc, argv, "-file", path);
  std::cout << "path: " << path << std::endl;
  if (path != "" && boost::filesystem::exists (path))
  {
    grabber.reset (new pcl::PCDGrabber<pcl::PointXYZRGBA> (path, frames_per_second, repeat));
  }
  else
  {
    std::vector<std::string> pcd_files;
    pcl::console::parse_argument (argc, argv, "-dir", path);
    std::cout << "path: " << path << std::endl;
    if (path != "" && boost::filesystem::exists (path))
    {
      boost::filesystem::directory_iterator end_itr;
      for (boost::filesystem::directory_iterator itr (path); itr != end_itr; ++itr)
      {
#if BOOST_FILESYSTEM_VERSION == 3
        if (!is_directory (itr->status ()) && boost::algorithm::to_upper_copy (boost::filesystem::extension (itr->path ())) == ".PCD" )
#else
        if (!is_directory (itr->status ()) && boost::algorithm::to_upper_copy (boost::filesystem::extension (itr->leaf ())) == ".PCD" )
#endif
        {
#if BOOST_FILESYSTEM_VERSION == 3
          pcd_files.push_back (itr->path ().string ());
          std::cout << "added: " << itr->path ().string () << std::endl;
#else
          pcd_files.push_back (itr->path ());
          std::cout << "added: " << itr->path () << std::endl;
#endif
        }
      }
    }
    else
    {
      std::cout << "Neither a pcd file given using the \"-file\" option, nor given a directory containing pcd files using the \"-dir\" option." << std::endl;
    }

    // Sort the read files by name
    sort (pcd_files.begin (), pcd_files.end ());
    grabber.reset (new pcl::PCDGrabber<pcl::PointXYZRGBA> (pcd_files, frames_per_second, repeat));
  }

  EventHelper h;
  boost::function<void(const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&) > f = boost::bind (&EventHelper::cloud_cb, &h, _1);
  boost::signals2::connection c1 = grabber->registerCallback (f);

  std::string mouse_msg_3D ("Mouse coordinates in PCL Visualizer");
  std::string key_msg_3D ("Key event for PCL Visualizer");

  cloud_viewer->registerMouseCallback (&mouse_callback, static_cast<void*> (&mouse_msg_3D));
  cloud_viewer->registerKeyboardCallback(&keyboard_callback, static_cast<void*> (&key_msg_3D));

  std::string mouse_msg_2D ("Mouse coordinates in image viewer");
  std::string key_msg_2D ("Key event for image viewer");

  img_viewer->registerMouseCallback (&mouse_callback, static_cast<void*> (&mouse_msg_2D));
  img_viewer->registerKeyboardCallback(&keyboard_callback, static_cast<void*> (&key_msg_2D));

  grabber->start ();
  while (!cloud_viewer->wasStopped ())
  {
    cloud_viewer->spinOnce ();

#if !((VTK_MAJOR_VERSION == 5)&&(VTK_MINOR_VERSION <= 4))
    img_viewer->spinOnce ();
#endif

    if (!cloud_)
    {
      boost::this_thread::sleep(boost::posix_time::microseconds(10000));
      continue;
    }

    if (mutex_.try_lock ())
    {
      pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr temp_cloud;
      temp_cloud.swap (cloud_);
      mutex_.unlock ();

#if !((VTK_MAJOR_VERSION == 5)&&(VTK_MINOR_VERSION <= 4))
      img_viewer->showRGBImage (*temp_cloud);
#endif

      if (!cloud_viewer->updatePointCloud (temp_cloud, "PCDCloud"))
      {
        cloud_viewer->addPointCloud (temp_cloud, "PCDCloud");
        cloud_viewer->resetCameraViewpoint ("PCDCloud");
      }
    }
  }

  grabber->stop ();
}
/* ]--- */
<commit_msg>fixes for 1.x<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  Copyright (c) 2012-, Open Perception, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 *
 */
#include <pcl/io/pcd_grabber.h>
#include <pcl/console/parse.h>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <pcl/console/print.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/visualization/image_viewer.h>

using pcl::console::print_error;
using pcl::console::print_info;
using pcl::console::print_value;

boost::mutex mutex_;
boost::shared_ptr<pcl::PCDGrabber<pcl::PointXYZRGBA> > grabber;
pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr cloud_;

void
printHelp (int, char **argv)
{
  //print_error ("Syntax is: %s <file_name 1..N>.pcd <options>\n", argv[0]);
  print_error ("Syntax is: %s <options>\n", argv[0]);
  print_info ("  where options are:\n");
  print_info ("                     -file file_name          = PCD file to be read from\n");
  print_info ("                     -dir directory_path      = directory path to PCD file(s) to be read from\n");
  print_info ("                     -fps frequency           = frames per second\n");
  print_info ("                     -repeat                  = optional parameter that tells wheter the PCD file(s) should be \"grabbed\" in a endless loop.\n");
  print_info ("\n");
  print_info ("                     -cam (*)                 = use given camera settings as initial view\n");
  print_info (stderr, " (*) [Clipping Range / Focal Point / Position / ViewUp / Distance / Window Size / Window Pos] or use a <filename.cam> that contains the same information.\n");
}

// Create the PCLVisualizer object
boost::shared_ptr<pcl::visualization::PCLVisualizer> cloud_viewer;
#if !((VTK_MAJOR_VERSION == 5)&&(VTK_MINOR_VERSION <= 4))
boost::shared_ptr<pcl::visualization::ImageViewer> img_viewer;
#endif

std::vector<double> fcolor_r, fcolor_b, fcolor_g;
bool fcolorparam = false;

struct EventHelper
{
  void
  cloud_cb (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr & cloud)
  {
    if (mutex_.try_lock ())
    {
      cloud_ = cloud;
      mutex_.unlock ();
    }
  }
};

void
keyboard_callback (const pcl::visualization::KeyboardEvent& event, void*)
{
  /// If SPACE is pressed, trigger new cloud callback (only works if framerate is set to 0)
  if (event.getKeyCode() == ' ' && grabber)
    grabber->trigger ();
}

void
mouse_callback (const pcl::visualization::MouseEvent& mouse_event, void* cookie)
{
  std::string* message = static_cast<std::string*> (cookie);
  if (mouse_event.getType() == pcl::visualization::MouseEvent::MouseButtonPress && mouse_event.getButton() == pcl::visualization::MouseEvent::LeftButton)
  {
    cout << (*message) << " :: " << mouse_event.getX () << " , " << mouse_event.getY () << endl;
  }
}

/* ---[ */
int
main (int argc, char** argv)
{
  srand (unsigned (time (0)));

  if (argc > 1)
  {
    for (int i = 1; i < argc; i++)
    {
      if (std::string (argv[i]) == "-h")
      {
        printHelp (argc, argv);
        return (-1);
      }
    }
  }

  // Command line parsing
  double bcolor[3] = {0, 0, 0};
  pcl::console::parse_3x_arguments (argc, argv, "-bc", bcolor[0], bcolor[1], bcolor[2]);

  fcolorparam = pcl::console::parse_multiple_3x_arguments (argc, argv, "-fc", fcolor_r, fcolor_g, fcolor_b);

  int psize = 0;
  pcl::console::parse_argument (argc, argv, "-ps", psize);

  double opaque;
  pcl::console::parse_argument (argc, argv, "-opaque", opaque);

  cloud_viewer.reset (new pcl::visualization::PCLVisualizer (argc, argv, "PCD viewer"));

#if !((VTK_MAJOR_VERSION == 5)&&(VTK_MINOR_VERSION <= 4))
  img_viewer.reset (new pcl::visualization::ImageViewer ("OpenNI Viewer"));
#endif

  //  // Change the cloud rendered point size
  //  if (psize > 0)
  //    p->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, psize, "OpenNICloud");
  //
  //  // Change the cloud rendered opacity
  //  if (opaque >= 0)
  //    p->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_OPACITY, opaque, "OpenNICloud");

  cloud_viewer->setBackgroundColor (bcolor[0], bcolor[1], bcolor[2]);

  // Read axes settings
  double axes = 0.0;
  pcl::console::parse_argument (argc, argv, "-ax", axes);
  if (axes != 0.0 && cloud_viewer)
  {
    float ax_x = 0.0, ax_y = 0.0, ax_z = 0.0;
    pcl::console::parse_3x_arguments (argc, argv, "-ax_pos", ax_x, ax_y, ax_z, false);
    // Draw XYZ axes if command-line enabled
    cloud_viewer->addCoordinateSystem (axes, ax_x, ax_y, ax_z);
  }

  float frames_per_second = 0; // 0 means only if triggered!
  pcl::console::parse (argc, argv, "-fps", frames_per_second);
  if (frames_per_second < 0)
    frames_per_second = 0.0;

  bool repeat = (pcl::console::find_argument (argc, argv, "-repeat") != -1);

  std::cout << "fps: " << frames_per_second << " , repeat: " << repeat << std::endl;
  std::string path = "";
  pcl::console::parse_argument (argc, argv, "-file", path);
  std::cout << "path: " << path << std::endl;
  if (path != "" && boost::filesystem::exists (path))
  {
    grabber.reset (new pcl::PCDGrabber<pcl::PointXYZRGBA> (path, frames_per_second, repeat));
  }
  else
  {
    std::vector<std::string> pcd_files;
    pcl::console::parse_argument (argc, argv, "-dir", path);
    std::cout << "path: " << path << std::endl;
    if (path != "" && boost::filesystem::exists (path))
    {
      boost::filesystem::directory_iterator end_itr;
      for (boost::filesystem::directory_iterator itr (path); itr != end_itr; ++itr)
      {
#if BOOST_FILESYSTEM_VERSION == 3
        if (!is_directory (itr->status ()) && boost::algorithm::to_upper_copy (boost::filesystem::extension (itr->path ())) == ".PCD" )
#else
        if (!is_directory (itr->status ()) && boost::algorithm::to_upper_copy (boost::filesystem::extension (itr->leaf ())) == ".PCD" )
#endif
        {
#if BOOST_FILESYSTEM_VERSION == 3
          pcd_files.push_back (itr->path ().string ());
          std::cout << "added: " << itr->path ().string () << std::endl;
#else
          pcd_files.push_back (itr->path ().string ());
          std::cout << "added: " << itr->path () << std::endl;
#endif
        }
      }
    }
    else
    {
      std::cout << "Neither a pcd file given using the \"-file\" option, nor given a directory containing pcd files using the \"-dir\" option." << std::endl;
    }

    // Sort the read files by name
    sort (pcd_files.begin (), pcd_files.end ());
    grabber.reset (new pcl::PCDGrabber<pcl::PointXYZRGBA> (pcd_files, frames_per_second, repeat));
  }

  EventHelper h;
  boost::function<void(const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&) > f = boost::bind (&EventHelper::cloud_cb, &h, _1);
  boost::signals2::connection c1 = grabber->registerCallback (f);

  std::string mouse_msg_3D ("Mouse coordinates in PCL Visualizer");
  std::string key_msg_3D ("Key event for PCL Visualizer");

  cloud_viewer->registerMouseCallback (&mouse_callback, static_cast<void*> (&mouse_msg_3D));
  cloud_viewer->registerKeyboardCallback(&keyboard_callback, static_cast<void*> (&key_msg_3D));

  std::string mouse_msg_2D ("Mouse coordinates in image viewer");
  std::string key_msg_2D ("Key event for image viewer");

#if !((VTK_MAJOR_VERSION == 5)&&(VTK_MINOR_VERSION <= 4))
  img_viewer->registerMouseCallback (&mouse_callback, static_cast<void*> (&mouse_msg_2D));
  img_viewer->registerKeyboardCallback(&keyboard_callback, static_cast<void*> (&key_msg_2D));
#endif

  grabber->start ();
  while (!cloud_viewer->wasStopped ())
  {
    cloud_viewer->spinOnce ();

#if !((VTK_MAJOR_VERSION == 5)&&(VTK_MINOR_VERSION <= 4))
    img_viewer->spinOnce ();
#endif

    if (!cloud_)
    {
      boost::this_thread::sleep(boost::posix_time::microseconds(10000));
      continue;
    }

    if (mutex_.try_lock ())
    {
      pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr temp_cloud;
      temp_cloud.swap (cloud_);
      mutex_.unlock ();

#if !((VTK_MAJOR_VERSION == 5)&&(VTK_MINOR_VERSION <= 4))
      img_viewer->showRGBImage (*temp_cloud);
#endif

      if (!cloud_viewer->updatePointCloud (temp_cloud, "PCDCloud"))
      {
        cloud_viewer->addPointCloud (temp_cloud, "PCDCloud");
        cloud_viewer->resetCameraViewpoint ("PCDCloud");
      }
    }
  }

  grabber->stop ();
}
/* ]--- */
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Radu Bogdan rusu, Suat Gedikli
 *
 */
// PCL
#include <Eigen/Geometry>
#include <pcl/common/common.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/pcd_grabber.h>
#include <cfloat>
#include <pcl/visualization/point_cloud_handlers.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/visualization/histogram_visualizer.h>
#include <pcl/terminal_tools/print.h>
#include <pcl/terminal_tools/parse.h>
#include <pcl/terminal_tools/time.h>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>

using terminal_tools::print_color;
using terminal_tools::print_error;
using terminal_tools::print_error;
using terminal_tools::print_warn;
using terminal_tools::print_info;
using terminal_tools::print_debug;
using terminal_tools::print_value;
using terminal_tools::print_highlight;
using terminal_tools::TT_BRIGHT;
using terminal_tools::TT_RED;
using terminal_tools::TT_GREEN;
using terminal_tools::TT_BLUE;
using namespace boost::filesystem;

typedef pcl_visualization::PointCloudColorHandler<pcl::PointCloud<pcl::PointXYZ> > ColorHandler;
typedef ColorHandler::Ptr ColorHandlerPtr;
typedef ColorHandler::ConstPtr ColorHandlerConstPtr;

typedef pcl_visualization::PointCloudGeometryHandler<pcl::PointCloud<pcl::PointXYZ> > GeometryHandler;
typedef GeometryHandler::Ptr GeometryHandlerPtr;
typedef GeometryHandler::ConstPtr GeometryHandlerConstPtr;
boost::mutex mutex_;

#define NORMALS_SCALE 0.01
#define PC_SCALE 0.001

void
printHelp (int argc, char **argv)
{
  //print_error ("Syntax is: %s <file_name 1..N>.pcd <options>\n", argv[0]);
  print_error ("Syntax is: %s <options>\n", argv[0]);
  print_info ("  where options are:\n");
  print_info ("                     -file file_name          = PCD file to be read from\n");
  print_info ("                     -dir directory_path      = directory path to PCD file(s) to be read from\n");
  print_info ("                     -fps frequency           = frames per second\n");
  print_info ("                     -repeat                  = optional parameter that tells wheter the PCD file(s) should be \"grabbed\" in a endless loop.\n");
  print_info ("                     -bc r,g,b                = background color\n");
  print_info ("                     -fc r,g,b                = foreground color\n");
  print_info ("                     -ps X                    = point size (");
  print_value ("1..64");
  print_info (") \n");
  print_info ("                     -opaque X                = rendered point cloud opacity (");
  print_value ("0..1");
  print_info (")\n");

  print_info ("                     -ax ");
  print_value ("n");
  print_info ("                    = enable on-screen display of ");
  print_color (stdout, TT_BRIGHT, TT_RED, "X");
  print_color (stdout, TT_BRIGHT, TT_GREEN, "Y");
  print_color (stdout, TT_BRIGHT, TT_BLUE, "Z");
  print_info (" axes and scale them to ");
  print_value ("n\n");
  print_info ("                     -ax_pos X,Y,Z            = if axes are enabled, set their X,Y,Z position in space (default ");
  print_value ("0,0,0");
  print_info (")\n");

  print_info ("\n");
  print_info ("                     -cam (*)                 = use given camera settings as initial view\n");
  print_info (stderr, " (*) [Clipping Range / Focal Point / Position / ViewUp / Distance / Window Size / Window Pos] or use a <filename.cam> that contains the same information.\n");

  print_info ("\n");
  print_info ("                     -multiview 0/1           = enable/disable auto-multi viewport rendering (default ");
  print_value ("disabled");
  print_info (")\n");
  print_info ("\n");

  print_info ("\n");
  print_info ("                     -normals 0/X             = disable/enable the display of every Xth point's surface normal as lines (default ");
  print_value ("disabled");
  print_info (")\n");
  print_info ("                     -normals_scale X         = resize the normal unit vector size to X (default ");
  print_value ("0.02");
  print_info (")\n");
  print_info ("\n");
  print_info ("                     -pc 0/X                  = disable/enable the display of every Xth point's principal curvatures as lines (default ");
  print_value ("disabled");
  print_info (")\n");
  print_info ("                     -pc_scale X              = resize the principal curvatures vectors size to X (default ");
  print_value ("0.02");
  print_info (")\n");
  print_info ("\n");

  print_info ("\n(Note: for multiple .pcd files, provide multiple -{fc,ps,opaque} parameters; they will be automatically assigned to the right file)\n");
}

// Create the PCLVisualizer object
boost::shared_ptr<pcl_visualization::PCLVisualizer> p;
ColorHandlerPtr color_handler;
GeometryHandlerPtr geometry_handler;
std::vector<double> fcolor_r, fcolor_b, fcolor_g;
bool fcolorparam = false;

struct EventHelper
{

  void cloud_cb (const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloud)
  {
    //std::cout << __PRETTY_FUNCTION__ << " " << cloud->width << std::endl;
    // Add the dataset with a XYZ and a random handler
    //  geometry_handler.reset (new pcl_visualization::PointCloudGeometryHandlerXYZ<pcl::PointCloud<pcl::PointXYZRGB> > (*cloud));

    //// If color was given, ues that
    //if (fcolorparam)
    //  color_handler.reset (new pcl_visualization::PointCloudColorHandlerCustom<pcl::PointCloud<pcl::PointXYZRGB> > (cloud, fcolor_r, fcolor_g, fcolor_b));
    //else
    //  color_handler.reset (new pcl_visualization::PointCloudColorHandlerRandom<pcl::PointCloud<pcl::PointXYZRGB> > (cloud));

    // Add the cloud to the renderer

    boost::mutex::scoped_lock lock (mutex_);
    if (!cloud)
      return;
    p->removePointCloud ("PCDCloud");
    p->addPointCloud (*cloud, "PCDCloud");
  }
};

/* ---[ */
int
main (int argc, char** argv)
{
  srand (time (0));

  if (argc > 1)
  {
    for (int i = 1; i < argc; i++)
    {
      if (std::string (argv[i]) == "-h")
      {
        printHelp (argc, argv);
        return (-1);
      }
    }
  }

  // Command line parsing
  double bcolor[3] = {0, 0, 0};
  terminal_tools::parse_3x_arguments (argc, argv, "-bc", bcolor[0], bcolor[1], bcolor[2]);

  fcolorparam = terminal_tools::parse_multiple_3x_arguments (argc, argv, "-fc", fcolor_r, fcolor_g, fcolor_b);

  int psize = 0;
  terminal_tools::parse_argument (argc, argv, "-ps", psize);

  double opaque;
  terminal_tools::parse_argument (argc, argv, "-opaque", opaque);

  p.reset (new pcl_visualization::PCLVisualizer (argc, argv, "PCD viewer"));

  //  // Change the cloud rendered point size
  //  if (psize > 0)
  //    p->setPointCloudRenderingProperties (pcl_visualization::PCL_VISUALIZER_POINT_SIZE, psize, "KinectCloud");
  //
  //  // Change the cloud rendered opacity
  //  if (opaque >= 0)
  //    p->setPointCloudRenderingProperties (pcl_visualization::PCL_VISUALIZER_OPACITY, opaque, "KinectCloud");

  p->setBackgroundColor (bcolor[0], bcolor[1], bcolor[2]);

  //boost::signals2::connection c = interface->registerCallback (boost::bind (&bla::blatestpointcloudrgb, *this, _1));
  //boost::function<void (boost::shared_ptr<pcl::PointCloud<pcl::PointXYZRGB> >)> f = boost::bind (&bla::blatestpointcloudrgb, this, _1);
  //boost::signals2::connection c =
  //  interface->registerCallback <void(boost::shared_ptr<pcl::PointCloud<pcl::PointXYZRGB> >)> (boost::bind (&bla::blatestpointcloudrgb, *this, _1).);

  // Read axes settings
  double axes = 0.0;
  terminal_tools::parse_argument (argc, argv, "-ax", axes);
  if (axes != 0.0 && p)
  {
    double ax_x = 0.0, ax_y = 0.0, ax_z = 0.0;
    terminal_tools::parse_3x_arguments (argc, argv, "-ax_pos", ax_x, ax_y, ax_z, false);
    // Draw XYZ axes if command-line enabled
    p->addCoordinateSystem (axes, ax_x, ax_y, ax_z);
  }

  pcl::Grabber* interface = 0;

  float frames_per_second = 0; // 0 means only if triggered!
  terminal_tools::parse (argc, argv, "-fps", frames_per_second);
  if (frames_per_second < 0)
    frames_per_second = 0.0;

  std::cout << terminal_tools::find_argument (argc, argv, "-repeat") << " : repaet" << std::endl;
  bool repeat = (terminal_tools::find_argument (argc, argv, "-repeat") != -1);

  std::cout << "fps: " << frames_per_second << " , repeat: " << repeat << std::endl;
  std::string path = "";
  terminal_tools::parse_argument (argc, argv, "-file", path);
  std::cout << "path: " << path << std::endl;
  if (path != "" && exists (path))
  {
    interface = new pcl::PCDGrabber<pcl::PointXYZ > (path, frames_per_second, repeat);
  }
  else
  {
    std::vector<std::string> pcd_files;
    terminal_tools::parse_argument (argc, argv, "-dir", path);
    std::cout << "path: " << path << std::endl;
    if (path != "" && exists (path))
    {
      directory_iterator end_itr;
      for (directory_iterator itr (path); itr != end_itr; ++itr)
      {
        if (!is_directory (itr->status()) && boost::algorithm::to_upper_copy(extension (itr->leaf())) == ".PCD" )
        {
          pcd_files.push_back (itr->path ().string());
          std::cout << "added: " << itr->path ().string() << std::endl;
        }
      }
    }
    else
    {
      std::cout << "Neither a pcd file given using the \"-file\" option, nor given a directory containing pcd files using the \"-dir\" option." << std::endl;
    }
    interface = new pcl::PCDGrabber<pcl::PointXYZ > (pcd_files, frames_per_second, repeat);
  }

  EventHelper h;
  boost::function<void(const pcl::PointCloud<pcl::PointXYZ>::ConstPtr&) > f = boost::bind (&EventHelper::cloud_cb, &h, _1);
  boost::signals2::connection c1 = interface->registerCallback (f);

  interface->start ();
  while (true)
  {
    usleep (10000);
    {
      boost::mutex::scoped_lock lock (mutex_);
      p->spinOnce ();
      if (p->wasStopped ())
        break;
    }
  }

  interface->stop ();
}
/* ]--- */
<commit_msg>Fix: force using boost::filesystem2 to fix bug 60 and 62 Note: gaurdians must be added to the line 287 to prevent using leaf methode 			while BOOST_VERSION >= 104600<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * Author: Radu Bogdan rusu, Suat Gedikli
 *
 */
// PCL
#include <Eigen/Geometry>
#include <pcl/common/common.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/pcd_grabber.h>
#include <cfloat>
#include <pcl/visualization/point_cloud_handlers.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/visualization/histogram_visualizer.h>
#include <pcl/terminal_tools/print.h>
#include <pcl/terminal_tools/parse.h>
#include <pcl/terminal_tools/time.h>
#define BOOST_FILESYSTEM_VERSION 2
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>

using terminal_tools::print_color;
using terminal_tools::print_error;
using terminal_tools::print_error;
using terminal_tools::print_warn;
using terminal_tools::print_info;
using terminal_tools::print_debug;
using terminal_tools::print_value;
using terminal_tools::print_highlight;
using terminal_tools::TT_BRIGHT;
using terminal_tools::TT_RED;
using terminal_tools::TT_GREEN;
using terminal_tools::TT_BLUE;
using namespace boost::filesystem;

typedef pcl_visualization::PointCloudColorHandler<pcl::PointCloud<pcl::PointXYZ> > ColorHandler;
typedef ColorHandler::Ptr ColorHandlerPtr;
typedef ColorHandler::ConstPtr ColorHandlerConstPtr;

typedef pcl_visualization::PointCloudGeometryHandler<pcl::PointCloud<pcl::PointXYZ> > GeometryHandler;
typedef GeometryHandler::Ptr GeometryHandlerPtr;
typedef GeometryHandler::ConstPtr GeometryHandlerConstPtr;
boost::mutex mutex_;

#define NORMALS_SCALE 0.01
#define PC_SCALE 0.001

void
printHelp (int argc, char **argv)
{
  //print_error ("Syntax is: %s <file_name 1..N>.pcd <options>\n", argv[0]);
  print_error ("Syntax is: %s <options>\n", argv[0]);
  print_info ("  where options are:\n");
  print_info ("                     -file file_name          = PCD file to be read from\n");
  print_info ("                     -dir directory_path      = directory path to PCD file(s) to be read from\n");
  print_info ("                     -fps frequency           = frames per second\n");
  print_info ("                     -repeat                  = optional parameter that tells wheter the PCD file(s) should be \"grabbed\" in a endless loop.\n");
  print_info ("                     -bc r,g,b                = background color\n");
  print_info ("                     -fc r,g,b                = foreground color\n");
  print_info ("                     -ps X                    = point size (");
  print_value ("1..64");
  print_info (") \n");
  print_info ("                     -opaque X                = rendered point cloud opacity (");
  print_value ("0..1");
  print_info (")\n");

  print_info ("                     -ax ");
  print_value ("n");
  print_info ("                    = enable on-screen display of ");
  print_color (stdout, TT_BRIGHT, TT_RED, "X");
  print_color (stdout, TT_BRIGHT, TT_GREEN, "Y");
  print_color (stdout, TT_BRIGHT, TT_BLUE, "Z");
  print_info (" axes and scale them to ");
  print_value ("n\n");
  print_info ("                     -ax_pos X,Y,Z            = if axes are enabled, set their X,Y,Z position in space (default ");
  print_value ("0,0,0");
  print_info (")\n");

  print_info ("\n");
  print_info ("                     -cam (*)                 = use given camera settings as initial view\n");
  print_info (stderr, " (*) [Clipping Range / Focal Point / Position / ViewUp / Distance / Window Size / Window Pos] or use a <filename.cam> that contains the same information.\n");

  print_info ("\n");
  print_info ("                     -multiview 0/1           = enable/disable auto-multi viewport rendering (default ");
  print_value ("disabled");
  print_info (")\n");
  print_info ("\n");

  print_info ("\n");
  print_info ("                     -normals 0/X             = disable/enable the display of every Xth point's surface normal as lines (default ");
  print_value ("disabled");
  print_info (")\n");
  print_info ("                     -normals_scale X         = resize the normal unit vector size to X (default ");
  print_value ("0.02");
  print_info (")\n");
  print_info ("\n");
  print_info ("                     -pc 0/X                  = disable/enable the display of every Xth point's principal curvatures as lines (default ");
  print_value ("disabled");
  print_info (")\n");
  print_info ("                     -pc_scale X              = resize the principal curvatures vectors size to X (default ");
  print_value ("0.02");
  print_info (")\n");
  print_info ("\n");

  print_info ("\n(Note: for multiple .pcd files, provide multiple -{fc,ps,opaque} parameters; they will be automatically assigned to the right file)\n");
}

// Create the PCLVisualizer object
boost::shared_ptr<pcl_visualization::PCLVisualizer> p;
ColorHandlerPtr color_handler;
GeometryHandlerPtr geometry_handler;
std::vector<double> fcolor_r, fcolor_b, fcolor_g;
bool fcolorparam = false;

struct EventHelper
{

  void cloud_cb (const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloud)
  {
    //std::cout << __PRETTY_FUNCTION__ << " " << cloud->width << std::endl;
    // Add the dataset with a XYZ and a random handler
    //  geometry_handler.reset (new pcl_visualization::PointCloudGeometryHandlerXYZ<pcl::PointCloud<pcl::PointXYZRGB> > (*cloud));

    //// If color was given, ues that
    //if (fcolorparam)
    //  color_handler.reset (new pcl_visualization::PointCloudColorHandlerCustom<pcl::PointCloud<pcl::PointXYZRGB> > (cloud, fcolor_r, fcolor_g, fcolor_b));
    //else
    //  color_handler.reset (new pcl_visualization::PointCloudColorHandlerRandom<pcl::PointCloud<pcl::PointXYZRGB> > (cloud));

    // Add the cloud to the renderer

    boost::mutex::scoped_lock lock (mutex_);
    if (!cloud)
      return;
    p->removePointCloud ("PCDCloud");
    p->addPointCloud (*cloud, "PCDCloud");
  }
};

/* ---[ */
int
main (int argc, char** argv)
{
  srand (time (0));

  if (argc > 1)
  {
    for (int i = 1; i < argc; i++)
    {
      if (std::string (argv[i]) == "-h")
      {
        printHelp (argc, argv);
        return (-1);
      }
    }
  }

  // Command line parsing
  double bcolor[3] = {0, 0, 0};
  terminal_tools::parse_3x_arguments (argc, argv, "-bc", bcolor[0], bcolor[1], bcolor[2]);

  fcolorparam = terminal_tools::parse_multiple_3x_arguments (argc, argv, "-fc", fcolor_r, fcolor_g, fcolor_b);

  int psize = 0;
  terminal_tools::parse_argument (argc, argv, "-ps", psize);

  double opaque;
  terminal_tools::parse_argument (argc, argv, "-opaque", opaque);

  p.reset (new pcl_visualization::PCLVisualizer (argc, argv, "PCD viewer"));

  //  // Change the cloud rendered point size
  //  if (psize > 0)
  //    p->setPointCloudRenderingProperties (pcl_visualization::PCL_VISUALIZER_POINT_SIZE, psize, "KinectCloud");
  //
  //  // Change the cloud rendered opacity
  //  if (opaque >= 0)
  //    p->setPointCloudRenderingProperties (pcl_visualization::PCL_VISUALIZER_OPACITY, opaque, "KinectCloud");

  p->setBackgroundColor (bcolor[0], bcolor[1], bcolor[2]);

  //boost::signals2::connection c = interface->registerCallback (boost::bind (&bla::blatestpointcloudrgb, *this, _1));
  //boost::function<void (boost::shared_ptr<pcl::PointCloud<pcl::PointXYZRGB> >)> f = boost::bind (&bla::blatestpointcloudrgb, this, _1);
  //boost::signals2::connection c =
  //  interface->registerCallback <void(boost::shared_ptr<pcl::PointCloud<pcl::PointXYZRGB> >)> (boost::bind (&bla::blatestpointcloudrgb, *this, _1).);

  // Read axes settings
  double axes = 0.0;
  terminal_tools::parse_argument (argc, argv, "-ax", axes);
  if (axes != 0.0 && p)
  {
    double ax_x = 0.0, ax_y = 0.0, ax_z = 0.0;
    terminal_tools::parse_3x_arguments (argc, argv, "-ax_pos", ax_x, ax_y, ax_z, false);
    // Draw XYZ axes if command-line enabled
    p->addCoordinateSystem (axes, ax_x, ax_y, ax_z);
  }

  pcl::Grabber* interface = 0;

  float frames_per_second = 0; // 0 means only if triggered!
  terminal_tools::parse (argc, argv, "-fps", frames_per_second);
  if (frames_per_second < 0)
    frames_per_second = 0.0;

  std::cout << terminal_tools::find_argument (argc, argv, "-repeat") << " : repaet" << std::endl;
  bool repeat = (terminal_tools::find_argument (argc, argv, "-repeat") != -1);

  std::cout << "fps: " << frames_per_second << " , repeat: " << repeat << std::endl;
  std::string path = "";
  terminal_tools::parse_argument (argc, argv, "-file", path);
  std::cout << "path: " << path << std::endl;
  if (path != "" && exists (path))
  {
    interface = new pcl::PCDGrabber<pcl::PointXYZ > (path, frames_per_second, repeat);
  }
  else
  {
    std::vector<std::string> pcd_files;
    terminal_tools::parse_argument (argc, argv, "-dir", path);
    std::cout << "path: " << path << std::endl;
    if (path != "" && exists (path))
    {
      directory_iterator end_itr;
      for (directory_iterator itr (path); itr != end_itr; ++itr)
      {
        if (!is_directory (itr->status()) && boost::algorithm::to_upper_copy(extension (itr->leaf())) == ".PCD" )
        {
          pcd_files.push_back (itr->path ().string());
          std::cout << "added: " << itr->path ().string() << std::endl;
        }
      }
    }
    else
    {
      std::cout << "Neither a pcd file given using the \"-file\" option, nor given a directory containing pcd files using the \"-dir\" option." << std::endl;
    }
    interface = new pcl::PCDGrabber<pcl::PointXYZ > (pcd_files, frames_per_second, repeat);
  }

  EventHelper h;
  boost::function<void(const pcl::PointCloud<pcl::PointXYZ>::ConstPtr&) > f = boost::bind (&EventHelper::cloud_cb, &h, _1);
  boost::signals2::connection c1 = interface->registerCallback (f);

  interface->start ();
  while (true)
  {
    usleep (10000);
    {
      boost::mutex::scoped_lock lock (mutex_);
      p->spinOnce ();
      if (p->wasStopped ())
        break;
    }
  }

  interface->stop ();
}
/* ]--- */
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osg/PrimitiveSet>
#include <osg/BufferObject>
#include <osg/State>

using namespace osg;

void DrawArrays::draw(State&, bool) const
{
    glDrawArrays(_mode,_first,_count);
}

void DrawArrays::accept(PrimitiveFunctor& functor) const
{
    functor.drawArrays(_mode,_first,_count);
}

void DrawArrays::accept(PrimitiveIndexFunctor& functor) const
{
    functor.drawArrays(_mode,_first,_count);
}

void DrawArrayLengths::draw(State&, bool) const
{
    GLint first = _first;
    for(VectorSizei::const_iterator itr=begin();
        itr!=end();
        ++itr)
    {
        glDrawArrays(_mode,first,*itr);
        first += *itr;
    }
}

void DrawArrayLengths::accept(PrimitiveFunctor& functor) const
{
    GLint first = _first;
    for(VectorSizei::const_iterator itr=begin();
        itr!=end();
        ++itr)
    {
        functor.drawArrays(_mode,first,*itr);
        first += *itr;
    }
}

void DrawArrayLengths::accept(PrimitiveIndexFunctor& functor) const
{
    GLint first = _first;
    for(VectorSizei::const_iterator itr=begin();
        itr!=end();
        ++itr)
    {
        functor.drawArrays(_mode,first,*itr);
        first += *itr;
    }
}

unsigned int DrawArrayLengths::getNumIndices() const
{
    unsigned int count = 0;
    for(VectorSizei::const_iterator itr=begin();
        itr!=end();
        ++itr)
    {
        count += *itr;
    }
    return count;
}

DrawElementsUByte::~DrawElementsUByte()
{
    for(unsigned int i=0;i<_vboList.size();++i)
    {
        if (_vboList[i] != 0)
        {
            BufferObject::deleteBufferObject(i,_vboList[i]);
            _vboList[i] = 0;
        }
    }
}

void DrawElementsUByte::draw(State& state, bool useVertexBufferObjects) const
{
    if (useVertexBufferObjects)
    {
        const BufferObject::Extensions* extensions = BufferObject::getExtensions(state.getContextID(), true);

        GLuint& buffer = _vboList[state.getContextID()];
        if (!buffer)
        {
            extensions->glGenBuffers(1, &buffer);
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
            extensions->glBufferData(GL_ELEMENT_ARRAY_BUFFER_ARB, size() * 1, &front(), GL_STATIC_DRAW_ARB);
        }
        else
        {
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
        }

        glDrawElements(_mode, size(), GL_UNSIGNED_BYTE, 0);
        extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
    }
    else
    {
        glDrawElements(_mode, size(), GL_UNSIGNED_BYTE, &front());
    }
}

void DrawElementsUByte::accept(PrimitiveFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUByte::accept(PrimitiveIndexFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUByte::offsetIndices(int offset)
{
    for(iterator itr=begin();
        itr!=end();
        ++itr)
    {
        *itr += offset;
    }
}

DrawElementsUShort::~DrawElementsUShort()
{
    for(unsigned int i=0;i<_vboList.size();++i)
    {
        if (_vboList[i] != 0)
        {
            BufferObject::deleteBufferObject(i,_vboList[i]);
            _vboList[i] = 0;
        }
    }
}

void DrawElementsUShort::draw(State& state, bool useVertexBufferObjects) const
{
    if (useVertexBufferObjects)
    {
        const BufferObject::Extensions* extensions = BufferObject::getExtensions(state.getContextID(), true);

        GLuint& buffer = _vboList[state.getContextID()];
        if (!buffer)
        {
            extensions->glGenBuffers(1, &buffer);
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
            extensions->glBufferData(GL_ELEMENT_ARRAY_BUFFER_ARB, size() * 2, &front(), GL_STATIC_DRAW_ARB);
        }
        else
        {
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
        }

        extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
        glDrawElements(_mode, size(), GL_UNSIGNED_SHORT, 0);
    }
    else
    {
        glDrawElements(_mode, size(), GL_UNSIGNED_SHORT, &front());
    }
}

void DrawElementsUShort::accept(PrimitiveFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUShort::accept(PrimitiveIndexFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUShort::offsetIndices(int offset)
{
    for(iterator itr=begin();
        itr!=end();
        ++itr)
    {
        *itr += offset;
    }
}

DrawElementsUInt::~DrawElementsUInt()
{
    for(unsigned int i=0;i<_vboList.size();++i)
    {
        if (_vboList[i] != 0)
        {
            BufferObject::deleteBufferObject(i,_vboList[i]);
            _vboList[i] = 0;
        }
    }
}

void DrawElementsUInt::draw(State& state, bool useVertexBufferObjects) const
{
    if (useVertexBufferObjects)
    {
        const BufferObject::Extensions* extensions = BufferObject::getExtensions(state.getContextID(), true);

        GLuint& buffer = _vboList[state.getContextID()];
        if (!buffer)
        {
            extensions->glGenBuffers(1, &buffer);
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
            extensions->glBufferData(GL_ELEMENT_ARRAY_BUFFER_ARB, size() * 4, &front(), GL_STATIC_DRAW_ARB);
        }
        else
        {
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
        }

        glDrawElements(_mode, size(), GL_UNSIGNED_INT, 0);
        extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
    }
    else
    {
        glDrawElements(_mode, size(), GL_UNSIGNED_INT, &front());
    }
}

void DrawElementsUInt::accept(PrimitiveFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUInt::accept(PrimitiveIndexFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUInt::offsetIndices(int offset)
{
    for(iterator itr=begin();
        itr!=end();
        ++itr)
    {
        *itr += offset;
    }
}
<commit_msg>Fixed position of glBindBuffer.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osg/PrimitiveSet>
#include <osg/BufferObject>
#include <osg/State>

using namespace osg;

void DrawArrays::draw(State&, bool) const
{
    glDrawArrays(_mode,_first,_count);
}

void DrawArrays::accept(PrimitiveFunctor& functor) const
{
    functor.drawArrays(_mode,_first,_count);
}

void DrawArrays::accept(PrimitiveIndexFunctor& functor) const
{
    functor.drawArrays(_mode,_first,_count);
}

void DrawArrayLengths::draw(State&, bool) const
{
    GLint first = _first;
    for(VectorSizei::const_iterator itr=begin();
        itr!=end();
        ++itr)
    {
        glDrawArrays(_mode,first,*itr);
        first += *itr;
    }
}

void DrawArrayLengths::accept(PrimitiveFunctor& functor) const
{
    GLint first = _first;
    for(VectorSizei::const_iterator itr=begin();
        itr!=end();
        ++itr)
    {
        functor.drawArrays(_mode,first,*itr);
        first += *itr;
    }
}

void DrawArrayLengths::accept(PrimitiveIndexFunctor& functor) const
{
    GLint first = _first;
    for(VectorSizei::const_iterator itr=begin();
        itr!=end();
        ++itr)
    {
        functor.drawArrays(_mode,first,*itr);
        first += *itr;
    }
}

unsigned int DrawArrayLengths::getNumIndices() const
{
    unsigned int count = 0;
    for(VectorSizei::const_iterator itr=begin();
        itr!=end();
        ++itr)
    {
        count += *itr;
    }
    return count;
}

DrawElementsUByte::~DrawElementsUByte()
{
    for(unsigned int i=0;i<_vboList.size();++i)
    {
        if (_vboList[i] != 0)
        {
            BufferObject::deleteBufferObject(i,_vboList[i]);
            _vboList[i] = 0;
        }
    }
}

void DrawElementsUByte::draw(State& state, bool useVertexBufferObjects) const
{
    if (useVertexBufferObjects)
    {
        const BufferObject::Extensions* extensions = BufferObject::getExtensions(state.getContextID(), true);

        GLuint& buffer = _vboList[state.getContextID()];
        if (!buffer)
        {
            extensions->glGenBuffers(1, &buffer);
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
            extensions->glBufferData(GL_ELEMENT_ARRAY_BUFFER_ARB, size() * 1, &front(), GL_STATIC_DRAW_ARB);
        }
        else
        {
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
        }

        glDrawElements(_mode, size(), GL_UNSIGNED_BYTE, 0);

        extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
    }
    else
    {
        glDrawElements(_mode, size(), GL_UNSIGNED_BYTE, &front());
    }
}

void DrawElementsUByte::accept(PrimitiveFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUByte::accept(PrimitiveIndexFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUByte::offsetIndices(int offset)
{
    for(iterator itr=begin();
        itr!=end();
        ++itr)
    {
        *itr += offset;
    }
}

DrawElementsUShort::~DrawElementsUShort()
{
    for(unsigned int i=0;i<_vboList.size();++i)
    {
        if (_vboList[i] != 0)
        {
            BufferObject::deleteBufferObject(i,_vboList[i]);
            _vboList[i] = 0;
        }
    }
}

void DrawElementsUShort::draw(State& state, bool useVertexBufferObjects) const
{
    if (useVertexBufferObjects)
    {
        const BufferObject::Extensions* extensions = BufferObject::getExtensions(state.getContextID(), true);

        GLuint& buffer = _vboList[state.getContextID()];
        if (!buffer)
        {
            extensions->glGenBuffers(1, &buffer);
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
            extensions->glBufferData(GL_ELEMENT_ARRAY_BUFFER_ARB, size() * 2, &front(), GL_STATIC_DRAW_ARB);
        }
        else
        {
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
        }

        glDrawElements(_mode, size(), GL_UNSIGNED_SHORT, 0);

        extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
    }
    else
    {
        glDrawElements(_mode, size(), GL_UNSIGNED_SHORT, &front());
    }
}

void DrawElementsUShort::accept(PrimitiveFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUShort::accept(PrimitiveIndexFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUShort::offsetIndices(int offset)
{
    for(iterator itr=begin();
        itr!=end();
        ++itr)
    {
        *itr += offset;
    }
}

DrawElementsUInt::~DrawElementsUInt()
{
    for(unsigned int i=0;i<_vboList.size();++i)
    {
        if (_vboList[i] != 0)
        {
            BufferObject::deleteBufferObject(i,_vboList[i]);
            _vboList[i] = 0;
        }
    }
}

void DrawElementsUInt::draw(State& state, bool useVertexBufferObjects) const
{
    if (useVertexBufferObjects)
    {
        const BufferObject::Extensions* extensions = BufferObject::getExtensions(state.getContextID(), true);

        GLuint& buffer = _vboList[state.getContextID()];
        if (!buffer)
        {
            extensions->glGenBuffers(1, &buffer);
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
            extensions->glBufferData(GL_ELEMENT_ARRAY_BUFFER_ARB, size() * 4, &front(), GL_STATIC_DRAW_ARB);
        }
        else
        {
            extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer);
        }

        glDrawElements(_mode, size(), GL_UNSIGNED_INT, 0);

        extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
    }
    else
    {
        glDrawElements(_mode, size(), GL_UNSIGNED_INT, &front());
    }
}

void DrawElementsUInt::accept(PrimitiveFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUInt::accept(PrimitiveIndexFunctor& functor) const
{
    if (!empty()) functor.drawElements(_mode,size(),&front());
}

void DrawElementsUInt::offsetIndices(int offset)
{
    for(iterator itr=begin();
        itr!=end();
        ++itr)
    {
        *itr += offset;
    }
}
<|endoftext|>


<commit_before>// Floating Temple
// Copyright 2015 Derek S. Snyder
//
// 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 "python/local_object_impl.h"

#include "third_party/Python-3.4.2/Include/Python.h"

#include <cstddef>
#include <string>
#include <vector>

#include "base/escape.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "include/c++/value.h"
#include "python/dict_local_object.h"
#include "python/false_local_object.h"
#include "python/get_serialized_object_type.h"
#include "python/interpreter_impl.h"
#include "python/list_local_object.h"
#include "python/long_local_object.h"
#include "python/make_value.h"
#include "python/method_context.h"
#include "python/none_local_object.h"
#include "python/proto/serialization.pb.h"
#include "python/python_gil_lock.h"
#include "python/thread_substitution.h"
#include "python/true_local_object.h"

using std::size_t;
using std::string;
using std::vector;

namespace floating_temple {
namespace python {

LocalObjectImpl::LocalObjectImpl(PyObject* py_object)
    : py_object_(CHECK_NOTNULL(py_object)) {
}

LocalObjectImpl::~LocalObjectImpl() {
  PythonGilLock lock;
  Py_DECREF(py_object_);
}

size_t LocalObjectImpl::Serialize(void* buffer, size_t buffer_size,
                                  SerializationContext* context) const {
  ObjectProto object_proto;
  PopulateObjectProto(&object_proto, context);

  const size_t byte_size = static_cast<size_t>(object_proto.ByteSize());
  if (byte_size <= buffer_size) {
    object_proto.SerializeWithCachedSizesToArray(static_cast<uint8*>(buffer));
  }

  return byte_size;
}

#define CALL_TP_METHOD0(method) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->method != nullptr); \
        CHECK_EQ(parameters.size(), 0u); \
        MakeReturnValue((*object_type->method)(py_object_), return_value); \
        return; \
      } \
    } while (false)

#define CALL_TP_METHOD1(method, param_type1) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->method != nullptr); \
        CHECK_EQ(parameters.size(), 1u); \
        MakeReturnValue( \
            (*object_type->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_TP_METHOD2(method, param_type1, param_type2) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->method != nullptr); \
        CHECK_EQ(parameters.size(), 2u); \
        MakeReturnValue( \
            (*object_type->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context), \
                ExtractValue<param_type2>(parameters[1], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_NB_METHOD0(method) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_number != nullptr); \
        CHECK(object_type->tp_as_number->method != nullptr); \
        CHECK_EQ(parameters.size(), 0u); \
        MakeReturnValue((*object_type->tp_as_number->method)(py_object_), \
                        return_value); \
        return; \
      } \
    } while (false)

#define CALL_NB_METHOD1(method, param_type1) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_number != nullptr); \
        CHECK(object_type->tp_as_number->method != nullptr); \
        CHECK_EQ(parameters.size(), 1u); \
        MakeReturnValue( \
            (*object_type->tp_as_number->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_NB_METHOD2(method, param_type1, param_type2) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_number != nullptr); \
        CHECK(object_type->tp_as_number->method != nullptr); \
        CHECK_EQ(parameters.size(), 2u); \
        MakeReturnValue( \
            (*object_type->tp_as_number->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context), \
                ExtractValue<param_type2>(parameters[1], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_SQ_METHOD0(method) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_sequence != nullptr); \
        CHECK(object_type->tp_as_sequence->method != nullptr); \
        CHECK_EQ(parameters.size(), 0u); \
        MakeReturnValue((*object_type->tp_as_sequence->method)(py_object_), \
                        return_value); \
        return; \
      } \
    } while (false)

#define CALL_SQ_METHOD1(method, param_type1) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_sequence != nullptr); \
        CHECK(object_type->tp_as_sequence->method != nullptr); \
        CHECK_EQ(parameters.size(), 1u); \
        MakeReturnValue( \
            (*object_type->tp_as_sequence->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_SQ_METHOD2(method, param_type1, param_type2) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_sequence != nullptr); \
        CHECK(object_type->tp_as_sequence->method != nullptr); \
        CHECK_EQ(parameters.size(), 2u); \
        MakeReturnValue( \
            (*object_type->tp_as_sequence->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context), \
                ExtractValue<param_type2>(parameters[1], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_MP_METHOD0(method) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_mapping != nullptr); \
        CHECK(object_type->tp_as_mapping->method != nullptr); \
        CHECK_EQ(parameters.size(), 0u); \
        MakeReturnValue((*object_type->tp_as_mapping->method)(py_object_), \
                        return_value); \
        return; \
      } \
    } while (false)

#define CALL_MP_METHOD1(method, param_type1) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_mapping != nullptr); \
        CHECK(object_type->tp_as_mapping->method != nullptr); \
        CHECK_EQ(parameters.size(), 1u); \
        MakeReturnValue( \
            (*object_type->tp_as_mapping->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_MP_METHOD2(method, param_type1, param_type2) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_mapping != nullptr); \
        CHECK(object_type->tp_as_mapping->method != nullptr); \
        CHECK_EQ(parameters.size(), 2u); \
        MakeReturnValue( \
            (*object_type->tp_as_mapping->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context), \
                ExtractValue<param_type2>(parameters[1], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

void LocalObjectImpl::InvokeMethod(Thread* thread,
                                   PeerObject* peer_object,
                                   const string& method_name,
                                   const vector<Value>& parameters,
                                   Value* return_value) {
  CHECK(thread != nullptr);
  CHECK(peer_object != nullptr);

  VLOG(3) << "Invoke method on local object: " << method_name;

  MethodContext method_context;
  ThreadSubstitution thread_substitution(InterpreterImpl::instance(), thread);

  PythonGilLock lock;

  const PyTypeObject* const object_type = Py_TYPE(py_object_);
  CHECK(object_type != nullptr);

  // TODO(dss): Consider using binary search instead of linear search to find
  // the method given its name.

  // TODO(dss): Fail gracefully if the peer passes the wrong number of
  // parameters, or the wrong types of parameters.

  CALL_TP_METHOD1(tp_getattr, char*);
  CALL_TP_METHOD2(tp_setattr, char*, PyObject*);
  CALL_TP_METHOD0(tp_repr);
  CALL_TP_METHOD0(tp_hash);
  CALL_TP_METHOD2(tp_call, PyObject*, PyObject*);
  CALL_TP_METHOD0(tp_str);
  CALL_TP_METHOD1(tp_getattro, PyObject*);
  CALL_TP_METHOD2(tp_setattro, PyObject*, PyObject*);
  CALL_TP_METHOD2(tp_richcompare, PyObject*, int);
  CALL_TP_METHOD0(tp_iter);
  CALL_TP_METHOD0(tp_iternext);
  CALL_TP_METHOD2(tp_descr_get, PyObject*, PyObject*);
  CALL_TP_METHOD2(tp_descr_set, PyObject*, PyObject*);
  CALL_TP_METHOD2(tp_init, PyObject*, PyObject*);

  CALL_NB_METHOD1(nb_add, PyObject*);
  CALL_NB_METHOD1(nb_subtract, PyObject*);
  CALL_NB_METHOD1(nb_multiply, PyObject*);
  CALL_NB_METHOD1(nb_remainder, PyObject*);
  CALL_NB_METHOD1(nb_divmod, PyObject*);
  CALL_NB_METHOD2(nb_power, PyObject*, PyObject*);
  CALL_NB_METHOD0(nb_negative);
  CALL_NB_METHOD0(nb_positive);
  CALL_NB_METHOD0(nb_absolute);
  CALL_NB_METHOD0(nb_bool);
  CALL_NB_METHOD0(nb_invert);
  CALL_NB_METHOD1(nb_lshift, PyObject*);
  CALL_NB_METHOD1(nb_rshift, PyObject*);
  CALL_NB_METHOD1(nb_and, PyObject*);
  CALL_NB_METHOD1(nb_xor, PyObject*);
  CALL_NB_METHOD1(nb_or, PyObject*);
  CALL_NB_METHOD0(nb_int);
  CALL_NB_METHOD0(nb_float);
  CALL_NB_METHOD1(nb_inplace_add, PyObject*);
  CALL_NB_METHOD1(nb_inplace_subtract, PyObject*);
  CALL_NB_METHOD1(nb_inplace_multiply, PyObject*);
  CALL_NB_METHOD1(nb_inplace_remainder, PyObject*);
  CALL_NB_METHOD2(nb_inplace_power, PyObject*, PyObject*);
  CALL_NB_METHOD1(nb_inplace_lshift, PyObject*);
  CALL_NB_METHOD1(nb_inplace_rshift, PyObject*);
  CALL_NB_METHOD1(nb_inplace_and, PyObject*);
  CALL_NB_METHOD1(nb_inplace_xor, PyObject*);
  CALL_NB_METHOD1(nb_inplace_or, PyObject*);
  CALL_NB_METHOD1(nb_floor_divide, PyObject*);
  CALL_NB_METHOD1(nb_true_divide, PyObject*);
  CALL_NB_METHOD1(nb_inplace_floor_divide, PyObject*);
  CALL_NB_METHOD1(nb_inplace_true_divide, PyObject*);
  CALL_NB_METHOD0(nb_index);

  CALL_SQ_METHOD0(sq_length);
  CALL_SQ_METHOD1(sq_concat, PyObject*);
  CALL_SQ_METHOD1(sq_repeat, Py_ssize_t);
  CALL_SQ_METHOD1(sq_item, Py_ssize_t);
  CALL_SQ_METHOD2(sq_ass_item, Py_ssize_t, PyObject*);
  CALL_SQ_METHOD1(sq_contains, PyObject*);
  CALL_SQ_METHOD1(sq_inplace_concat, PyObject*);
  CALL_SQ_METHOD1(sq_inplace_repeat, Py_ssize_t);

  CALL_MP_METHOD0(mp_length);
  CALL_MP_METHOD1(mp_subscript, PyObject*);
  CALL_MP_METHOD2(mp_ass_subscript, PyObject*, PyObject*);

  // TODO(dss): Fail gracefully if a remote peer sends an invalid method name.
  LOG(FATAL) << "Unexpected method name \"" << CEscape(method_name) << "\"";
}

#undef CALL_TP_METHOD0
#undef CALL_TP_METHOD1
#undef CALL_TP_METHOD2
#undef CALL_NB_METHOD0
#undef CALL_NB_METHOD1
#undef CALL_NB_METHOD2
#undef CALL_SQ_METHOD0
#undef CALL_SQ_METHOD1
#undef CALL_SQ_METHOD2
#undef CALL_MP_METHOD0
#undef CALL_MP_METHOD1
#undef CALL_MP_METHOD2

// static
LocalObjectImpl* LocalObjectImpl::Deserialize(const void* buffer,
                                              size_t buffer_size,
                                              DeserializationContext* context) {
  CHECK(buffer != nullptr);

  ObjectProto object_proto;
  CHECK(object_proto.ParseFromArray(buffer, buffer_size));

  const ObjectProto::Type object_type = GetSerializedObjectType(object_proto);

  switch (object_type) {
    case ObjectProto::PY_NONE:
      return new NoneLocalObject();

    case ObjectProto::LONG:
      return LongLocalObject::ParseLongProto(object_proto.long_object());

    case ObjectProto::FALSE:
      return new FalseLocalObject();

    case ObjectProto::TRUE:
      return new TrueLocalObject();

    case ObjectProto::LIST:
      return ListLocalObject::ParseListProto(object_proto.list_object(),
                                             context);

    case ObjectProto::DICT:
      return DictLocalObject::ParseDictProto(object_proto.dict_object(),
                                             context);

    case ObjectProto::FLOAT:
    case ObjectProto::COMPLEX:
    case ObjectProto::BYTES:
    case ObjectProto::BYTE_ARRAY:
    case ObjectProto::UNICODE:
    case ObjectProto::TUPLE:
    case ObjectProto::SET:
    case ObjectProto::FROZEN_SET:
    case ObjectProto::UNSERIALIZABLE:
      LOG(FATAL) << "Not yet implemented";
      return nullptr;

    default:
      LOG(FATAL) << "Unexpected object type: " << static_cast<int>(object_type);
  }

  return nullptr;
}

}  // namespace python
}  // namespace floating_temple
<commit_msg>Add more detailed debug log output for the case where a Python object can't be deserialized.<commit_after>// Floating Temple
// Copyright 2015 Derek S. Snyder
//
// 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 "python/local_object_impl.h"

#include "third_party/Python-3.4.2/Include/Python.h"

#include <cstddef>
#include <string>
#include <vector>

#include "base/escape.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "include/c++/value.h"
#include "python/dict_local_object.h"
#include "python/false_local_object.h"
#include "python/get_serialized_object_type.h"
#include "python/interpreter_impl.h"
#include "python/list_local_object.h"
#include "python/long_local_object.h"
#include "python/make_value.h"
#include "python/method_context.h"
#include "python/none_local_object.h"
#include "python/proto/serialization.pb.h"
#include "python/python_gil_lock.h"
#include "python/thread_substitution.h"
#include "python/true_local_object.h"

using std::size_t;
using std::string;
using std::vector;

namespace floating_temple {
namespace python {

LocalObjectImpl::LocalObjectImpl(PyObject* py_object)
    : py_object_(CHECK_NOTNULL(py_object)) {
}

LocalObjectImpl::~LocalObjectImpl() {
  PythonGilLock lock;
  Py_DECREF(py_object_);
}

size_t LocalObjectImpl::Serialize(void* buffer, size_t buffer_size,
                                  SerializationContext* context) const {
  ObjectProto object_proto;
  PopulateObjectProto(&object_proto, context);

  const size_t byte_size = static_cast<size_t>(object_proto.ByteSize());
  if (byte_size <= buffer_size) {
    object_proto.SerializeWithCachedSizesToArray(static_cast<uint8*>(buffer));
  }

  return byte_size;
}

#define CALL_TP_METHOD0(method) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->method != nullptr); \
        CHECK_EQ(parameters.size(), 0u); \
        MakeReturnValue((*object_type->method)(py_object_), return_value); \
        return; \
      } \
    } while (false)

#define CALL_TP_METHOD1(method, param_type1) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->method != nullptr); \
        CHECK_EQ(parameters.size(), 1u); \
        MakeReturnValue( \
            (*object_type->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_TP_METHOD2(method, param_type1, param_type2) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->method != nullptr); \
        CHECK_EQ(parameters.size(), 2u); \
        MakeReturnValue( \
            (*object_type->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context), \
                ExtractValue<param_type2>(parameters[1], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_NB_METHOD0(method) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_number != nullptr); \
        CHECK(object_type->tp_as_number->method != nullptr); \
        CHECK_EQ(parameters.size(), 0u); \
        MakeReturnValue((*object_type->tp_as_number->method)(py_object_), \
                        return_value); \
        return; \
      } \
    } while (false)

#define CALL_NB_METHOD1(method, param_type1) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_number != nullptr); \
        CHECK(object_type->tp_as_number->method != nullptr); \
        CHECK_EQ(parameters.size(), 1u); \
        MakeReturnValue( \
            (*object_type->tp_as_number->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_NB_METHOD2(method, param_type1, param_type2) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_number != nullptr); \
        CHECK(object_type->tp_as_number->method != nullptr); \
        CHECK_EQ(parameters.size(), 2u); \
        MakeReturnValue( \
            (*object_type->tp_as_number->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context), \
                ExtractValue<param_type2>(parameters[1], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_SQ_METHOD0(method) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_sequence != nullptr); \
        CHECK(object_type->tp_as_sequence->method != nullptr); \
        CHECK_EQ(parameters.size(), 0u); \
        MakeReturnValue((*object_type->tp_as_sequence->method)(py_object_), \
                        return_value); \
        return; \
      } \
    } while (false)

#define CALL_SQ_METHOD1(method, param_type1) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_sequence != nullptr); \
        CHECK(object_type->tp_as_sequence->method != nullptr); \
        CHECK_EQ(parameters.size(), 1u); \
        MakeReturnValue( \
            (*object_type->tp_as_sequence->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_SQ_METHOD2(method, param_type1, param_type2) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_sequence != nullptr); \
        CHECK(object_type->tp_as_sequence->method != nullptr); \
        CHECK_EQ(parameters.size(), 2u); \
        MakeReturnValue( \
            (*object_type->tp_as_sequence->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context), \
                ExtractValue<param_type2>(parameters[1], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_MP_METHOD0(method) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_mapping != nullptr); \
        CHECK(object_type->tp_as_mapping->method != nullptr); \
        CHECK_EQ(parameters.size(), 0u); \
        MakeReturnValue((*object_type->tp_as_mapping->method)(py_object_), \
                        return_value); \
        return; \
      } \
    } while (false)

#define CALL_MP_METHOD1(method, param_type1) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_mapping != nullptr); \
        CHECK(object_type->tp_as_mapping->method != nullptr); \
        CHECK_EQ(parameters.size(), 1u); \
        MakeReturnValue( \
            (*object_type->tp_as_mapping->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

#define CALL_MP_METHOD2(method, param_type1, param_type2) \
    do { \
      if (method_name == #method) { \
        CHECK(object_type->tp_as_mapping != nullptr); \
        CHECK(object_type->tp_as_mapping->method != nullptr); \
        CHECK_EQ(parameters.size(), 2u); \
        MakeReturnValue( \
            (*object_type->tp_as_mapping->method)( \
                py_object_, \
                ExtractValue<param_type1>(parameters[0], &method_context), \
                ExtractValue<param_type2>(parameters[1], &method_context)), \
            return_value); \
        return; \
      } \
    } while (false)

void LocalObjectImpl::InvokeMethod(Thread* thread,
                                   PeerObject* peer_object,
                                   const string& method_name,
                                   const vector<Value>& parameters,
                                   Value* return_value) {
  CHECK(thread != nullptr);
  CHECK(peer_object != nullptr);

  VLOG(3) << "Invoke method on local object: " << method_name;

  MethodContext method_context;
  ThreadSubstitution thread_substitution(InterpreterImpl::instance(), thread);

  PythonGilLock lock;

  const PyTypeObject* const object_type = Py_TYPE(py_object_);
  CHECK(object_type != nullptr);

  // TODO(dss): Consider using binary search instead of linear search to find
  // the method given its name.

  // TODO(dss): Fail gracefully if the peer passes the wrong number of
  // parameters, or the wrong types of parameters.

  CALL_TP_METHOD1(tp_getattr, char*);
  CALL_TP_METHOD2(tp_setattr, char*, PyObject*);
  CALL_TP_METHOD0(tp_repr);
  CALL_TP_METHOD0(tp_hash);
  CALL_TP_METHOD2(tp_call, PyObject*, PyObject*);
  CALL_TP_METHOD0(tp_str);
  CALL_TP_METHOD1(tp_getattro, PyObject*);
  CALL_TP_METHOD2(tp_setattro, PyObject*, PyObject*);
  CALL_TP_METHOD2(tp_richcompare, PyObject*, int);
  CALL_TP_METHOD0(tp_iter);
  CALL_TP_METHOD0(tp_iternext);
  CALL_TP_METHOD2(tp_descr_get, PyObject*, PyObject*);
  CALL_TP_METHOD2(tp_descr_set, PyObject*, PyObject*);
  CALL_TP_METHOD2(tp_init, PyObject*, PyObject*);

  CALL_NB_METHOD1(nb_add, PyObject*);
  CALL_NB_METHOD1(nb_subtract, PyObject*);
  CALL_NB_METHOD1(nb_multiply, PyObject*);
  CALL_NB_METHOD1(nb_remainder, PyObject*);
  CALL_NB_METHOD1(nb_divmod, PyObject*);
  CALL_NB_METHOD2(nb_power, PyObject*, PyObject*);
  CALL_NB_METHOD0(nb_negative);
  CALL_NB_METHOD0(nb_positive);
  CALL_NB_METHOD0(nb_absolute);
  CALL_NB_METHOD0(nb_bool);
  CALL_NB_METHOD0(nb_invert);
  CALL_NB_METHOD1(nb_lshift, PyObject*);
  CALL_NB_METHOD1(nb_rshift, PyObject*);
  CALL_NB_METHOD1(nb_and, PyObject*);
  CALL_NB_METHOD1(nb_xor, PyObject*);
  CALL_NB_METHOD1(nb_or, PyObject*);
  CALL_NB_METHOD0(nb_int);
  CALL_NB_METHOD0(nb_float);
  CALL_NB_METHOD1(nb_inplace_add, PyObject*);
  CALL_NB_METHOD1(nb_inplace_subtract, PyObject*);
  CALL_NB_METHOD1(nb_inplace_multiply, PyObject*);
  CALL_NB_METHOD1(nb_inplace_remainder, PyObject*);
  CALL_NB_METHOD2(nb_inplace_power, PyObject*, PyObject*);
  CALL_NB_METHOD1(nb_inplace_lshift, PyObject*);
  CALL_NB_METHOD1(nb_inplace_rshift, PyObject*);
  CALL_NB_METHOD1(nb_inplace_and, PyObject*);
  CALL_NB_METHOD1(nb_inplace_xor, PyObject*);
  CALL_NB_METHOD1(nb_inplace_or, PyObject*);
  CALL_NB_METHOD1(nb_floor_divide, PyObject*);
  CALL_NB_METHOD1(nb_true_divide, PyObject*);
  CALL_NB_METHOD1(nb_inplace_floor_divide, PyObject*);
  CALL_NB_METHOD1(nb_inplace_true_divide, PyObject*);
  CALL_NB_METHOD0(nb_index);

  CALL_SQ_METHOD0(sq_length);
  CALL_SQ_METHOD1(sq_concat, PyObject*);
  CALL_SQ_METHOD1(sq_repeat, Py_ssize_t);
  CALL_SQ_METHOD1(sq_item, Py_ssize_t);
  CALL_SQ_METHOD2(sq_ass_item, Py_ssize_t, PyObject*);
  CALL_SQ_METHOD1(sq_contains, PyObject*);
  CALL_SQ_METHOD1(sq_inplace_concat, PyObject*);
  CALL_SQ_METHOD1(sq_inplace_repeat, Py_ssize_t);

  CALL_MP_METHOD0(mp_length);
  CALL_MP_METHOD1(mp_subscript, PyObject*);
  CALL_MP_METHOD2(mp_ass_subscript, PyObject*, PyObject*);

  // TODO(dss): Fail gracefully if a remote peer sends an invalid method name.
  LOG(FATAL) << "Unexpected method name \"" << CEscape(method_name) << "\"";
}

#undef CALL_TP_METHOD0
#undef CALL_TP_METHOD1
#undef CALL_TP_METHOD2
#undef CALL_NB_METHOD0
#undef CALL_NB_METHOD1
#undef CALL_NB_METHOD2
#undef CALL_SQ_METHOD0
#undef CALL_SQ_METHOD1
#undef CALL_SQ_METHOD2
#undef CALL_MP_METHOD0
#undef CALL_MP_METHOD1
#undef CALL_MP_METHOD2

// static
LocalObjectImpl* LocalObjectImpl::Deserialize(const void* buffer,
                                              size_t buffer_size,
                                              DeserializationContext* context) {
  CHECK(buffer != nullptr);

  ObjectProto object_proto;
  CHECK(object_proto.ParseFromArray(buffer, buffer_size));

  const ObjectProto::Type object_type = GetSerializedObjectType(object_proto);

  switch (object_type) {
    case ObjectProto::PY_NONE:
      return new NoneLocalObject();

    case ObjectProto::LONG:
      return LongLocalObject::ParseLongProto(object_proto.long_object());

    case ObjectProto::FALSE:
      return new FalseLocalObject();

    case ObjectProto::TRUE:
      return new TrueLocalObject();

    case ObjectProto::LIST:
      return ListLocalObject::ParseListProto(object_proto.list_object(),
                                             context);

    case ObjectProto::DICT:
      return DictLocalObject::ParseDictProto(object_proto.dict_object(),
                                             context);

    case ObjectProto::FLOAT:
    case ObjectProto::COMPLEX:
    case ObjectProto::BYTES:
    case ObjectProto::BYTE_ARRAY:
    case ObjectProto::UNICODE:
    case ObjectProto::TUPLE:
    case ObjectProto::SET:
    case ObjectProto::FROZEN_SET:
      LOG(FATAL) << "Not yet implemented (object_type == "
                 << static_cast<int>(object_type) << ")";
      return nullptr;

    case ObjectProto::UNSERIALIZABLE:
      LOG(FATAL) << "The object is unserializable.";
      return nullptr;

    default:
      LOG(FATAL) << "Unexpected object type: " << static_cast<int>(object_type);
  }

  return nullptr;
}

}  // namespace python
}  // namespace floating_temple
<|endoftext|>


<commit_before>#ifndef VAST_DATA_HPP
#define VAST_DATA_HPP

#include <chrono>
#include <iterator>
#include <regex>
#include <string>
#include <vector>
#include <map>
#include <type_traits>

#include "vast/aliases.hpp"
#include "vast/address.hpp"
#include "vast/pattern.hpp"
#include "vast/subnet.hpp"
#include "vast/port.hpp"
#include "vast/none.hpp"
#include "vast/offset.hpp"
#include "vast/optional.hpp"
#include "vast/time.hpp"
#include "vast/type.hpp"
#include "vast/variant.hpp"
#include "vast/detail/flat_set.hpp"
#include "vast/detail/operators.hpp"
#include "vast/detail/string.hpp"

namespace vast {

class data;
class json;

namespace detail {

template <class T>
using make_data_type = std::conditional_t<
    std::is_floating_point<T>::value,
    real,
    std::conditional_t<
      std::is_same<T, boolean>::value,
      boolean,
      std::conditional_t<
        std::is_unsigned<T>::value,
        count,
        std::conditional_t<
          std::is_signed<T>::value,
          integer,
          std::conditional_t<
            std::is_convertible<T, std::string>::value,
            std::string,
            std::conditional_t<
                 std::is_same<T, none>::value
              || std::is_same<T, timespan>::value
              || std::is_same<T, timestamp>::value
              || std::is_same<T, pattern>::value
              || std::is_same<T, address>::value
              || std::is_same<T, subnet>::value
              || std::is_same<T, port>::value
              || std::is_same<T, enumeration>::value
              || std::is_same<T, vector>::value
              || std::is_same<T, set>::value
              || std::is_same<T, table>::value,
              T,
              std::false_type
            >
          >
        >
      >
    >
  >;

using data_variant = variant<
  none,
  boolean,
  integer,
  count,
  real,
  timespan,
  timestamp,
  std::string,
  pattern,
  address,
  subnet,
  port,
  enumeration,
  vector,
  set,
  table
>;

} // namespace detail

/// Converts a C++ type to the corresponding VAST data type.
template <class T>
using data_type = detail::make_data_type<std::decay_t<T>>;

/// A type-erased represenation of various types of data.
class data : detail::totally_ordered<data>,
             detail::addable<data> {
  friend access;

public:
  /// Default-constructs empty data.
  data(none = nil);

  /// Constructs data from optional data.
  /// @param x The optional data instance.
  template <class T>
  data(optional<T> x) : data{x ? std::move(*x) : data{}} {
  }

  /// Constructs data from a `std::chrono::duration`.
  /// @param x The duration to construct data from.
  template <class Rep, class Period>
  data(std::chrono::duration<Rep, Period> x) : data_{timespan{x}} {
  }

  /// Constructs data.
  /// @param x The instance to construct data from.
  template <
    class T,
    class = detail::disable_if_t<
      detail::is_same_or_derived<data, T>::value
      || std::is_same<data_type<T>, std::false_type>::value
    >
  >
  data(T&& x)
    : data_(data_type<T>(std::forward<T>(x))) {
  }

  data& operator+=(data const& rhs);

  friend bool operator==(data const& lhs, data const& rhs);
  friend bool operator<(data const& lhs, data const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector&f, data& d) {
    return f(d.data_);
  }

  friend detail::data_variant& expose(data& d);

private:
  detail::data_variant data_;
};

//template <class T>
//using is_basic_data = std::integral_constant<
//    bool,
//    std::is_same<T, boolean>::value
//      || std::is_same<T, integer>::value
//      || std::is_same<T, count>::value
//      || std::is_same<T, real>::value
//      || std::is_same<T, timespan>::value
//      || std::is_same<T, timestamp>::value
//      || std::is_same<T, std::string>::value
//      || std::is_same<T, pattern>::value
//      || std::is_same<T, address>::value
//      || std::is_same<T, subnet>::value
//      || std::is_same<T, port>::value
//  >;
//
//template <class T>
//using is_container_data = std::integral_constant<
//    bool,
//    std::is_same<T, vector>::value
//      || std::is_same<T, set>::value
//      || std::is_same<T, table>::value
//  >;

// -- helpers -----------------------------------------------------------------

/// Retrieves data at a given offset.
/// @param v The vector to lookup.
/// @param o The offset to access.
/// @returns A pointer to the data at *o* or `nullptr` if *o* does not
///          describe a valid offset.
data const* get(vector const& v, offset const& o);
data const* get(data const& d, offset const& o);

/// Flattens a vector.
/// @param xs The vector to flatten.
/// @returns The flattened vector.
/// @see unflatten
vector flatten(vector const& xs);
vector flatten(vector&& xs);

/// Flattens a vector.
/// @param x The vector to flatten.
/// @returns The flattened vector as `data` if *x* is a `vector`.
/// @see unflatten
data flatten(data const& x);
data flatten(data&& x);

/// Unflattens a vector according to a record type.
/// @param xs The vector to unflatten according to *rt*.
/// @param rt The type that defines the vector structure.
/// @returns The unflattened vector of *xs* according to *rt*.
/// @see flatten
optional<vector> unflatten(vector const& xs, record_type const& rt);
optional<vector> unflatten(vector&& xs, record_type const& rt);

/// Unflattens a vector according to a record type.
/// @param x The vector to unflatten according to *t*.
/// @param t The type that defines the vector structure.
/// @returns The unflattened vector of *x* according to *t* if *x* is a
///          `vector` and *t* a `record_type`.
/// @see flatten
optional<vector> unflatten(data const& x, type const& t);
optional<vector> unflatten(data&& x, type const& t);

/// Evaluates a data predicate.
/// @param lhs The LHS of the predicate.
/// @param op The relational operator.
/// @param rhs The RHS of the predicate.
bool evaluate(data const& lhs, relational_operator op, data const& rhs);

// -- convertible -------------------------------------------------------------

bool convert(vector const& v, json& j);
bool convert(set const& v, json& j);
bool convert(table const& v, json& j);
bool convert(data const& v, json& j);

/// Converts data with a type to "zipped" JSON, i.e., the JSON object for
/// records contains the field names from the type corresponding to the given
/// data.
bool convert(data const& v, json& j, type const& t);

} // namespace vast

#endif
<commit_msg>Make data hashable<commit_after>#ifndef VAST_DATA_HPP
#define VAST_DATA_HPP

#include <chrono>
#include <iterator>
#include <regex>
#include <string>
#include <vector>
#include <map>
#include <type_traits>

#include "vast/concept/hashable/uhash.hpp"
#include "vast/concept/hashable/xxhash.hpp"

#include "vast/aliases.hpp"
#include "vast/address.hpp"
#include "vast/pattern.hpp"
#include "vast/subnet.hpp"
#include "vast/port.hpp"
#include "vast/none.hpp"
#include "vast/offset.hpp"
#include "vast/optional.hpp"
#include "vast/time.hpp"
#include "vast/type.hpp"
#include "vast/variant.hpp"
#include "vast/detail/flat_set.hpp"
#include "vast/detail/operators.hpp"
#include "vast/detail/string.hpp"

namespace vast {

class data;
class json;

namespace detail {

template <class T>
using make_data_type = std::conditional_t<
    std::is_floating_point<T>::value,
    real,
    std::conditional_t<
      std::is_same<T, boolean>::value,
      boolean,
      std::conditional_t<
        std::is_unsigned<T>::value,
        count,
        std::conditional_t<
          std::is_signed<T>::value,
          integer,
          std::conditional_t<
            std::is_convertible<T, std::string>::value,
            std::string,
            std::conditional_t<
                 std::is_same<T, none>::value
              || std::is_same<T, timespan>::value
              || std::is_same<T, timestamp>::value
              || std::is_same<T, pattern>::value
              || std::is_same<T, address>::value
              || std::is_same<T, subnet>::value
              || std::is_same<T, port>::value
              || std::is_same<T, enumeration>::value
              || std::is_same<T, vector>::value
              || std::is_same<T, set>::value
              || std::is_same<T, table>::value,
              T,
              std::false_type
            >
          >
        >
      >
    >
  >;

using data_variant = variant<
  none,
  boolean,
  integer,
  count,
  real,
  timespan,
  timestamp,
  std::string,
  pattern,
  address,
  subnet,
  port,
  enumeration,
  vector,
  set,
  table
>;

} // namespace detail

/// Converts a C++ type to the corresponding VAST data type.
template <class T>
using data_type = detail::make_data_type<std::decay_t<T>>;

/// A type-erased represenation of various types of data.
class data : detail::totally_ordered<data>,
             detail::addable<data> {
  friend access;

public:
  /// Default-constructs empty data.
  data(none = nil);

  /// Constructs data from optional data.
  /// @param x The optional data instance.
  template <class T>
  data(optional<T> x) : data{x ? std::move(*x) : data{}} {
  }

  /// Constructs data from a `std::chrono::duration`.
  /// @param x The duration to construct data from.
  template <class Rep, class Period>
  data(std::chrono::duration<Rep, Period> x) : data_{timespan{x}} {
  }

  /// Constructs data.
  /// @param x The instance to construct data from.
  template <
    class T,
    class = detail::disable_if_t<
      detail::is_same_or_derived<data, T>::value
      || std::is_same<data_type<T>, std::false_type>::value
    >
  >
  data(T&& x)
    : data_(data_type<T>(std::forward<T>(x))) {
  }

  data& operator+=(data const& rhs);

  friend bool operator==(data const& lhs, data const& rhs);
  friend bool operator<(data const& lhs, data const& rhs);

  template <class Inspector>
  friend auto inspect(Inspector&f, data& d) {
    return f(d.data_);
  }

  friend detail::data_variant& expose(data& d);

private:
  detail::data_variant data_;
};

//template <class T>
//using is_basic_data = std::integral_constant<
//    bool,
//    std::is_same<T, boolean>::value
//      || std::is_same<T, integer>::value
//      || std::is_same<T, count>::value
//      || std::is_same<T, real>::value
//      || std::is_same<T, timespan>::value
//      || std::is_same<T, timestamp>::value
//      || std::is_same<T, std::string>::value
//      || std::is_same<T, pattern>::value
//      || std::is_same<T, address>::value
//      || std::is_same<T, subnet>::value
//      || std::is_same<T, port>::value
//  >;
//
//template <class T>
//using is_container_data = std::integral_constant<
//    bool,
//    std::is_same<T, vector>::value
//      || std::is_same<T, set>::value
//      || std::is_same<T, table>::value
//  >;

// -- helpers -----------------------------------------------------------------

/// Retrieves data at a given offset.
/// @param v The vector to lookup.
/// @param o The offset to access.
/// @returns A pointer to the data at *o* or `nullptr` if *o* does not
///          describe a valid offset.
data const* get(vector const& v, offset const& o);
data const* get(data const& d, offset const& o);

/// Flattens a vector.
/// @param xs The vector to flatten.
/// @returns The flattened vector.
/// @see unflatten
vector flatten(vector const& xs);
vector flatten(vector&& xs);

/// Flattens a vector.
/// @param x The vector to flatten.
/// @returns The flattened vector as `data` if *x* is a `vector`.
/// @see unflatten
data flatten(data const& x);
data flatten(data&& x);

/// Unflattens a vector according to a record type.
/// @param xs The vector to unflatten according to *rt*.
/// @param rt The type that defines the vector structure.
/// @returns The unflattened vector of *xs* according to *rt*.
/// @see flatten
optional<vector> unflatten(vector const& xs, record_type const& rt);
optional<vector> unflatten(vector&& xs, record_type const& rt);

/// Unflattens a vector according to a record type.
/// @param x The vector to unflatten according to *t*.
/// @param t The type that defines the vector structure.
/// @returns The unflattened vector of *x* according to *t* if *x* is a
///          `vector` and *t* a `record_type`.
/// @see flatten
optional<vector> unflatten(data const& x, type const& t);
optional<vector> unflatten(data&& x, type const& t);

/// Evaluates a data predicate.
/// @param lhs The LHS of the predicate.
/// @param op The relational operator.
/// @param rhs The RHS of the predicate.
bool evaluate(data const& lhs, relational_operator op, data const& rhs);

// -- convertible -------------------------------------------------------------

bool convert(vector const& v, json& j);
bool convert(set const& v, json& j);
bool convert(table const& v, json& j);
bool convert(data const& v, json& j);

/// Converts data with a type to "zipped" JSON, i.e., the JSON object for
/// records contains the field names from the type corresponding to the given
/// data.
bool convert(data const& v, json& j, type const& t);

} // namespace vast

namespace std {

template <>
struct hash<vast::data> {
  size_t operator()(const vast::data& x) const {
    return vast::uhash<vast::xxhash>{}(x);
  }
};

} // namespace std

#endif
<|endoftext|>