<commit_before>#include "ShapefileLoader.h"

#include "PointCloud.h"
#include "MultiArcGraph.h"
#include "PlanarGraph.h"
#include "ArcData2D.h"

#include <Table.h>
#include <DBase3File.h>

#include <cassert>
#include <shapefil.h>
#include <iostream>
#include <cmath>
#include <sstream>

using namespace std;
using namespace table;

ShapefileLoader::ShapefileLoader() : FileTypeHandler("ESRI Shapefile", false) {
  addExtension("shp");
}

std::shared_ptr<Graph>
ShapefileLoader::openGraph(const char * filename) {
  SHPHandle shp = SHPOpen(filename, "rb");
  if (!shp) {
    cerr << "failed to open shapefile\n";
    return 0;
  }

  double minb[4], maxb[4];
  int shape_count, global_shape_type;
  SHPGetInfo(shp, &shape_count, &global_shape_type, minb, maxb);

  std::shared_ptr<Graph> graph;

  map<string, int> nodes;
  map<string, pair<glm::dvec2, set<string> > > node_edges;
  map<string, int> waiting_faces;

  cerr << "loading shapefile (" << shape_count << ")\n";

  bool has_polygons = false;

  for (int i = 0; i < shape_count; i++) {
    SHPObject * o = SHPReadObject(shp, i);
    assert(o);
    int shape_dimensions;

    switch (o->nSHPType) {
    case SHPT_POINT:
    case SHPT_POINTZ:
    case SHPT_POINTM:
    case SHPT_MULTIPOINT:
    case SHPT_MULTIPOINTZ:
    case SHPT_MULTIPOINTM:
      shape_dimensions = 0;
      if (!graph.get()) {
	cerr << "creating pointcloud for shapefile\n";
	graph = std::make_shared<PointCloud>();
	graph->setHasSpatialData(true);
      }
      assert(shape_dimensions == graph->getDimensions());
      for (int j = 0; j < o->nVertices; j++) {
	double x = o->padfX[j], y = o->padfY[j], z = o->padfZ[j];
	createNode2D(*graph, nodes, x, y);
      }
      break;
    case SHPT_ARC: // = polyline
    case SHPT_ARCZ:
    case SHPT_ARCM:
      shape_dimensions = 1;
      if (!graph.get()) {
	cerr << "creating undirected graph for shapefile\n";
	graph = std::make_shared<MultiArcGraph>();
	graph->setHasSpatialData(true);
	graph->setHasArcData(true);
	graph->setNodeVisibility(false);
      }
      assert(shape_dimensions == graph->getDimensions());
      {
	int hyperedge_id = graph->addFace(-1);
	for (int j = 0; j < o->nParts; j++) {
	  int start = o->nParts > 1 ? o->panPartStart[j] : 0;
	  int end = o->nParts > 1 && j + 1 < o->nParts ? o->panPartStart[j + 1] : o->nVertices;
	  ArcData2D arc;
	  for (int k0 = start; k0 < end; k0++) {
	    double x = o->padfX[k0], y = o->padfY[k0], z = o->padfZ[k0];
	    arc.data.push_back(glm::dvec2(x, y));
	  }

	  int arc_id = graph->addArcGeometry(arc);
	  pair<int, int> n = createNodesForArc(arc, *graph, nodes);
	  assert(arc_id);
	  assert(arc_id >= 1 && arc_id <= graph->getArcGeometry().size());
	  int edge_id = graph->addEdge(n.first, n.second, hyperedge_id, 1.0f, arc_id);
	  assert(graph->getEdgeAttributes(edge_id).arc == arc_id);
	}
      }
      break;
    case SHPT_POLYGON:
    case SHPT_POLYGONZ:
    case SHPT_POLYGONM:
      shape_dimensions = 2;
      if (!graph.get()) {
	cerr << "creating planar graph for shapefile\n";
	graph = std::make_shared<PlanarGraph>();
	graph->setHasSpatialData(true);
	graph->setHasArcData(true);
	graph->setNodeVisibility(false);
	graph->setEdgeVisibility(false);
	// graph->addUniversalRegion();
      }
      assert(shape_dimensions == graph->getDimensions());
      has_polygons = true;
      for (int j = 0; j < o->nParts; j++) {
	int start = o->nParts > 1 ? o->panPartStart[j] : 0;
	int end = o->nParts > 1 && j + 1 < o->nParts ? o->panPartStart[j + 1] : o->nVertices;
	int n = end - start;
	for (int k0 = 0; k0 + 1 < n; k0++) {
	  int k1 = start + (k0 % n), k2 = start + ((k0 + 1) % n);
	  glm::dvec2 v1(o->padfX[k1], o->padfY[k1]); //, o->padfZ[k]);
	  glm::dvec2 v2(o->padfX[k2], o->padfY[k2]); // o->padfZ[k + 1]);
	  ostringstream key1, key2;
	  key1 << v1.x << "/" << v1.y;
	  key2 << v2.x << "/" << v2.y;
	  pair<glm::dvec2, set<string> > & ne1 = node_edges[key1.str()];
	  pair<glm::dvec2, set<string> > & ne2 = node_edges[key2.str()];
	  ne1.first = v1;
	  ne2.first = v2;
	  ne1.second.insert(key2.str());
	  ne2.second.insert(key1.str());
	}
      }
      break;
    case SHPT_MULTIPATCH:
      cerr << "multipatches not supported\n";
      assert(0);
      break;
    default:
      cerr << "unhandled type\n";
      assert(0);
    }
    SHPDestroyObject(o);
  }

  if (has_polygons) {
    cerr << "creating nodes (" << node_edges.size() << ")\n";
    for (map<string, pair<glm::dvec2, set<string> > >::iterator it = node_edges.begin(); it != node_edges.end(); it++) {
      if (it->second.second.size() >= 3) {
	createNode2D(*graph, nodes, it->second.first.x, it->second.first.y);
      }
    }
    cerr << "creating faces\n";
    for (int i = 0; i < shape_count; i++) {
      SHPObject * o = SHPReadObject(shp, i);
      assert(o);
      assert(o->nSHPType == SHPT_POLYGON || o->nSHPType == SHPT_POLYGONZ || o->nSHPType == SHPT_POLYGONM);
      int region_id = graph->addRegion();
      assert(o->nParts >= 1); // could be zero to
      for (int j = 0; j < o->nParts; j++) {
	int face_id = graph->addFace(region_id);
	// cerr << "handling polygon " << i << ", part " << j << endl;
	int start = o->panPartStart[j];
	if (j == 0 && start > 0) {
	  cerr << "invalid start " << start << endl;
	  start = 0;
	}
	int end = j + 1 < o->nParts ? o->panPartStart[j + 1] : o->nVertices;
	list<glm::dvec2> input;
      	double area = 0, centroid_x = 0, centroid_y = 0;
	for (int k = start; k < end; k++) {
	  double x = o->padfX[k], y = o->padfY[k], z = o->padfZ[k];
	  input.push_back(glm::dvec2(x, y));
	  if (k + 1 < end) {
	    double a = o->padfX[k] * o->padfY[k + 1] - o->padfY[k] * o->padfX[k + 1];
	    area -= a;
	    centroid_x -= (o->padfX[k] + o->padfX[k + 1]) * a;
	    centroid_y -= (o->padfY[k] + o->padfY[k + 1]) * a;
	  }
	}
	area *= 0.5;
	centroid_x /= (6.0*area);
	centroid_y /= (6.0*area);
	graph->setFaceCentroid(face_id, glm::vec2(centroid_x, centroid_y));
	if (input.size() > 1 &&
	    input.front().x == input.back().x &&
	    input.front().y == input.back().y) {
	  input.pop_back();
	}
	// cerr << "rolling vertices (" << input.size() << ")\n";
	bool node_found = false;
	for (int step = 0; step < input.size(); step++) {
	  ostringstream key1;
	  key1 << input.front().x << "/" << input.front().y;
	  if (nodes.find(key1.str()) != nodes.end()) {
	    node_found = true;
	    break;
	  } else {
	    input.push_back(input.front());
	    input.pop_front();
	  }
	}
	input.push_back(input.front());
	assert(input.size() >= 4);
	if (!node_found) { // island
	  createNode2D(*graph, nodes, input.front().x, input.front().y);
	}
	// ArcData2D arc;
	// for (list<glm::dvec3>::iterator it = input.begin(); it != input.end(); it++) {
	//   arc.data.push_back(*it);
	// }
	// pair<int, int> n = createNodesForArc(arc, graph, nodes);
	// assert(n.first == n.second);
	// int edge_id = graph->addEdge(n.first, n.second, face_id);
	// geometries.setArc(edge_id, arc);
	vector<ArcData2D> arcs;
	vector<int> face_nodes;
	for (auto & v : input) {
	  ostringstream key1;
	  key1 << v.x << "/" << v.y;
	  map<string, int>::iterator it2 = nodes.find(key1.str());
	  if (it2 != nodes.end()) {
	    if (!arcs.empty()) {
	      arcs.back().data.push_back(v);
	    }
	    face_nodes.push_back(it2->second);
	    arcs.push_back(ArcData2D());
	  }
	  assert(!arcs.empty());
	  arcs.back().data.push_back(v);
	}
	assert(face_nodes.front() == face_nodes.back());
	for (int l = 0; l + 1 < face_nodes.size(); l++) {
	  int node1 = face_nodes[l], node2 = face_nodes[l + 1];
	  if (node1 == node2) {
	    // cerr << "same nodes, size = " << face_nodes.size() << endl;
	  }
	  ostringstream key1, key2;
	  key1 << node1 << "/" << node2;
	  map<string, int>::iterator it = waiting_faces.find(key1.str());
	  if (it != waiting_faces.end()) {
	    int edge = it->second;
	    graph->setEdgeFace(edge, face_id);
	    graph->updateMBR(edge);
	    waiting_faces.erase(it);
	  } else {
	    key2 << node2 << "/" << node1;
	    it = waiting_faces.find(key2.str());
	    if (it != waiting_faces.end()) {
	      int edge = it->second;
	      graph->setEdgeFace(edge, face_id);
	      graph->updateMBR(edge);
	      waiting_faces.erase(it);
	    } else {
	      int arc_id = graph->addArcGeometry(arcs[l]);
	      assert(arc_id);
	      assert(arc_id >= 1 && arc_id <= graph->getArcGeometry().size());
	      int edge_id = graph->addEdge(node1, node2, face_id, 1.0f, arc_id);
	      // cerr << "created edge: id = " << edge_id << ", arc = " << arc_id << ", arc2 = " << graph->getEdgeAttributes(edge_id).arc << endl;
	      assert(graph->getEdgeAttributes(edge_id).arc == arc_id);
	      // waiting_faces[key1.str()] = edge_id;
	      // geometries.setArc(edge_id, arcs[l]);
	      graph->updateMBR(edge_id);
	    }
	  }
	}
      }
      SHPDestroyObject(o);
    }
  }

  SHPClose(shp);

  assert(graph.get());

  auto dbf = std::make_shared<DBase3File>(filename);

  if (dbf->getRecordCount() != shape_count) {
    cerr << "bad number of records\n";
  }

  if (graph->getDimensions() == 0) {
    Table & nodes_table = graph->getNodeData();
    for (auto & col : dbf->getColumns()) {
      nodes_table.addColumn(col);
    }
  } else if (graph->getDimensions() == 1) {
    Table & hyperedges_table = graph->getFaceData();
    for (auto & col : dbf->getColumns()) {
      hyperedges_table.addColumn(col);
    }
  } else if (graph->getDimensions() == 2) {
    Table & regions_table = graph->getRegionData();
    for (auto & col : dbf->getColumns()) {
      regions_table.addColumn(col);
    }
  } else {
    assert(0);
  }

  return graph;
}
<commit_msg>create NodeArray for each graph type<commit_after>#include "ShapefileLoader.h"

#include "PointCloud.h"
#include "MultiArcGraph.h"
#include "PlanarGraph.h"
#include "ArcData2D.h"

#include <Table.h>
#include <DBase3File.h>

#include <cassert>
#include <shapefil.h>
#include <iostream>
#include <cmath>
#include <sstream>

using namespace std;
using namespace table;

ShapefileLoader::ShapefileLoader() : FileTypeHandler("ESRI Shapefile", false) {
  addExtension("shp");
}

std::shared_ptr<Graph>
ShapefileLoader::openGraph(const char * filename) {
  SHPHandle shp = SHPOpen(filename, "rb");
  if (!shp) {
    cerr << "failed to open shapefile\n";
    return 0;
  }

  double minb[4], maxb[4];
  int shape_count, global_shape_type;
  SHPGetInfo(shp, &shape_count, &global_shape_type, minb, maxb);

  std::shared_ptr<Graph> graph;

  map<string, int> nodes;
  map<string, pair<glm::dvec2, set<string> > > node_edges;
  map<string, int> waiting_faces;

  cerr << "loading shapefile (" << shape_count << ")\n";

  bool has_polygons = false;

  for (int i = 0; i < shape_count; i++) {
    SHPObject * o = SHPReadObject(shp, i);
    assert(o);
    int shape_dimensions;

    switch (o->nSHPType) {
    case SHPT_POINT:
    case SHPT_POINTZ:
    case SHPT_POINTM:
    case SHPT_MULTIPOINT:
    case SHPT_MULTIPOINTZ:
    case SHPT_MULTIPOINTM:
      shape_dimensions = 0;
      if (!graph.get()) {
	cerr << "creating pointcloud for shapefile\n";
	graph = std::make_shared<PointCloud>();
	graph->setNodeArray(std::make_shared<NodeArray>());
	graph->setHasSpatialData(true);
      }
      assert(shape_dimensions == graph->getDimensions());
      for (int j = 0; j < o->nVertices; j++) {
	double x = o->padfX[j], y = o->padfY[j], z = o->padfZ[j];
	createNode2D(*graph, nodes, x, y);
      }
      break;
    case SHPT_ARC: // = polyline
    case SHPT_ARCZ:
    case SHPT_ARCM:
      shape_dimensions = 1;
      if (!graph.get()) {
	cerr << "creating undirected graph for shapefile\n";
	graph = std::make_shared<MultiArcGraph>();
	graph->setNodeArray(std::make_shared<NodeArray>());
	graph->setHasSpatialData(true);
	graph->setHasArcData(true);
	graph->setNodeVisibility(false);
      }
      assert(shape_dimensions == graph->getDimensions());
      {
	int hyperedge_id = graph->addFace(-1);
	for (int j = 0; j < o->nParts; j++) {
	  int start = o->nParts > 1 ? o->panPartStart[j] : 0;
	  int end = o->nParts > 1 && j + 1 < o->nParts ? o->panPartStart[j + 1] : o->nVertices;
	  ArcData2D arc;
	  for (int k0 = start; k0 < end; k0++) {
	    double x = o->padfX[k0], y = o->padfY[k0], z = o->padfZ[k0];
	    arc.data.push_back(glm::dvec2(x, y));
	  }

	  int arc_id = graph->addArcGeometry(arc);
	  pair<int, int> n = createNodesForArc(arc, *graph, nodes);
	  assert(arc_id);
	  assert(arc_id >= 1 && arc_id <= graph->getArcGeometry().size());
	  int edge_id = graph->addEdge(n.first, n.second, hyperedge_id, 1.0f, arc_id);
	  assert(graph->getEdgeAttributes(edge_id).arc == arc_id);
	}
      }
      break;
    case SHPT_POLYGON:
    case SHPT_POLYGONZ:
    case SHPT_POLYGONM:
      shape_dimensions = 2;
      if (!graph.get()) {
	cerr << "creating planar graph for shapefile\n";
	graph = std::make_shared<PlanarGraph>();
	graph->setNodeArray(std::make_shared<NodeArray>());
	graph->setHasSpatialData(true);
	graph->setHasArcData(true);
	graph->setNodeVisibility(false);
	graph->setEdgeVisibility(false);
	// graph->addUniversalRegion();
      }
      assert(shape_dimensions == graph->getDimensions());
      has_polygons = true;
      for (int j = 0; j < o->nParts; j++) {
	int start = o->nParts > 1 ? o->panPartStart[j] : 0;
	int end = o->nParts > 1 && j + 1 < o->nParts ? o->panPartStart[j + 1] : o->nVertices;
	int n = end - start;
	for (int k0 = 0; k0 + 1 < n; k0++) {
	  int k1 = start + (k0 % n), k2 = start + ((k0 + 1) % n);
	  glm::dvec2 v1(o->padfX[k1], o->padfY[k1]); //, o->padfZ[k]);
	  glm::dvec2 v2(o->padfX[k2], o->padfY[k2]); // o->padfZ[k + 1]);
	  ostringstream key1, key2;
	  key1 << v1.x << "/" << v1.y;
	  key2 << v2.x << "/" << v2.y;
	  pair<glm::dvec2, set<string> > & ne1 = node_edges[key1.str()];
	  pair<glm::dvec2, set<string> > & ne2 = node_edges[key2.str()];
	  ne1.first = v1;
	  ne2.first = v2;
	  ne1.second.insert(key2.str());
	  ne2.second.insert(key1.str());
	}
      }
      break;
    case SHPT_MULTIPATCH:
      cerr << "multipatches not supported\n";
      assert(0);
      break;
    default:
      cerr << "unhandled type\n";
      assert(0);
    }
    SHPDestroyObject(o);
  }

  if (has_polygons) {
    cerr << "creating nodes (" << node_edges.size() << ")\n";
    for (map<string, pair<glm::dvec2, set<string> > >::iterator it = node_edges.begin(); it != node_edges.end(); it++) {
      if (it->second.second.size() >= 3) {
	createNode2D(*graph, nodes, it->second.first.x, it->second.first.y);
      }
    }
    cerr << "creating faces\n";
    for (int i = 0; i < shape_count; i++) {
      SHPObject * o = SHPReadObject(shp, i);
      assert(o);
      assert(o->nSHPType == SHPT_POLYGON || o->nSHPType == SHPT_POLYGONZ || o->nSHPType == SHPT_POLYGONM);
      int region_id = graph->addRegion();
      assert(o->nParts >= 1); // could be zero to
      for (int j = 0; j < o->nParts; j++) {
	int face_id = graph->addFace(region_id);
	// cerr << "handling polygon " << i << ", part " << j << endl;
	int start = o->panPartStart[j];
	if (j == 0 && start > 0) {
	  cerr << "invalid start " << start << endl;
	  start = 0;
	}
	int end = j + 1 < o->nParts ? o->panPartStart[j + 1] : o->nVertices;
	list<glm::dvec2> input;
      	double area = 0, centroid_x = 0, centroid_y = 0;
	for (int k = start; k < end; k++) {
	  double x = o->padfX[k], y = o->padfY[k], z = o->padfZ[k];
	  input.push_back(glm::dvec2(x, y));
	  if (k + 1 < end) {
	    double a = o->padfX[k] * o->padfY[k + 1] - o->padfY[k] * o->padfX[k + 1];
	    area -= a;
	    centroid_x -= (o->padfX[k] + o->padfX[k + 1]) * a;
	    centroid_y -= (o->padfY[k] + o->padfY[k + 1]) * a;
	  }
	}
	area *= 0.5;
	centroid_x /= (6.0*area);
	centroid_y /= (6.0*area);
	graph->setFaceCentroid(face_id, glm::vec2(centroid_x, centroid_y));
	if (input.size() > 1 &&
	    input.front().x == input.back().x &&
	    input.front().y == input.back().y) {
	  input.pop_back();
	}
	// cerr << "rolling vertices (" << input.size() << ")\n";
	bool node_found = false;
	for (int step = 0; step < input.size(); step++) {
	  ostringstream key1;
	  key1 << input.front().x << "/" << input.front().y;
	  if (nodes.find(key1.str()) != nodes.end()) {
	    node_found = true;
	    break;
	  } else {
	    input.push_back(input.front());
	    input.pop_front();
	  }
	}
	input.push_back(input.front());
	assert(input.size() >= 4);
	if (!node_found) { // island
	  createNode2D(*graph, nodes, input.front().x, input.front().y);
	}
	// ArcData2D arc;
	// for (list<glm::dvec3>::iterator it = input.begin(); it != input.end(); it++) {
	//   arc.data.push_back(*it);
	// }
	// pair<int, int> n = createNodesForArc(arc, graph, nodes);
	// assert(n.first == n.second);
	// int edge_id = graph->addEdge(n.first, n.second, face_id);
	// geometries.setArc(edge_id, arc);
	vector<ArcData2D> arcs;
	vector<int> face_nodes;
	for (auto & v : input) {
	  ostringstream key1;
	  key1 << v.x << "/" << v.y;
	  map<string, int>::iterator it2 = nodes.find(key1.str());
	  if (it2 != nodes.end()) {
	    if (!arcs.empty()) {
	      arcs.back().data.push_back(v);
	    }
	    face_nodes.push_back(it2->second);
	    arcs.push_back(ArcData2D());
	  }
	  assert(!arcs.empty());
	  arcs.back().data.push_back(v);
	}
	assert(face_nodes.front() == face_nodes.back());
	for (int l = 0; l + 1 < face_nodes.size(); l++) {
	  int node1 = face_nodes[l], node2 = face_nodes[l + 1];
	  if (node1 == node2) {
	    // cerr << "same nodes, size = " << face_nodes.size() << endl;
	  }
	  ostringstream key1, key2;
	  key1 << node1 << "/" << node2;
	  map<string, int>::iterator it = waiting_faces.find(key1.str());
	  if (it != waiting_faces.end()) {
	    int edge = it->second;
	    graph->setEdgeFace(edge, face_id);
	    graph->updateMBR(edge);
	    waiting_faces.erase(it);
	  } else {
	    key2 << node2 << "/" << node1;
	    it = waiting_faces.find(key2.str());
	    if (it != waiting_faces.end()) {
	      int edge = it->second;
	      graph->setEdgeFace(edge, face_id);
	      graph->updateMBR(edge);
	      waiting_faces.erase(it);
	    } else {
	      int arc_id = graph->addArcGeometry(arcs[l]);
	      assert(arc_id);
	      assert(arc_id >= 1 && arc_id <= graph->getArcGeometry().size());
	      int edge_id = graph->addEdge(node1, node2, face_id, 1.0f, arc_id);
	      // cerr << "created edge: id = " << edge_id << ", arc = " << arc_id << ", arc2 = " << graph->getEdgeAttributes(edge_id).arc << endl;
	      assert(graph->getEdgeAttributes(edge_id).arc == arc_id);
	      // waiting_faces[key1.str()] = edge_id;
	      // geometries.setArc(edge_id, arcs[l]);
	      graph->updateMBR(edge_id);
	    }
	  }
	}
      }
      SHPDestroyObject(o);
    }
  }

  SHPClose(shp);

  assert(graph.get());

  auto dbf = std::make_shared<DBase3File>(filename);

  if (dbf->getRecordCount() != shape_count) {
    cerr << "bad number of records\n";
  }

  if (graph->getDimensions() == 0) {
    Table & nodes_table = graph->getNodeData();
    for (auto & col : dbf->getColumns()) {
      nodes_table.addColumn(col);
    }
  } else if (graph->getDimensions() == 1) {
    Table & hyperedges_table = graph->getFaceData();
    for (auto & col : dbf->getColumns()) {
      hyperedges_table.addColumn(col);
    }
  } else if (graph->getDimensions() == 2) {
    Table & regions_table = graph->getRegionData();
    for (auto & col : dbf->getColumns()) {
      regions_table.addColumn(col);
    }
  } else {
    assert(0);
  }

  return graph;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkRRect.h"

namespace skiagm {

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

class RRectGM : public GM {
public:
    RRectGM(bool doAA, bool doClip) : fDoAA(doAA), fDoClip(doClip) {
        this->setBGColor(0xFFDDDDDD);
        this->setUpRRects();
    }

protected:
    SkString onShortName() {
        SkString name("rrect");
        if (fDoClip) {
            name.append("_clip");
        }
        if (fDoAA) {
            name.append("_aa");
        } else {
            name.append("_bw");
        }

        return name;
    }

    virtual SkISize onISize() { return make_isize(kImageWidth, kImageHeight); }

    virtual void onDraw(SkCanvas* canvas) {

        SkPaint paint;
        // when clipping the AA is pushed into the clip operation
        paint.setAntiAlias(fDoClip ? false : fDoAA);

        static const SkRect kMaxTileBound = SkRect::MakeWH(SkIntToScalar(kTileX), SkIntToScalar(kTileY));

        int curRRect = 0;
        for (int y = 1; y < kImageHeight; y += kTileY) {
            for (int x = 1; x < kImageWidth; x += kTileX) {
                if (curRRect >= kNumRRects) {
                    break;
                }
                SkASSERT(kMaxTileBound.contains(fRRects[curRRect].getBounds()));

                canvas->save();
                    canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
                    if (fDoClip) {
                        canvas->clipRRect(fRRects[curRRect], SkRegion::kReplace_Op, fDoAA);
                        canvas->drawRect(kMaxTileBound, paint);
                    } else {
                        canvas->drawRRect(fRRects[curRRect], paint);
                    }
                    ++curRRect;
                canvas->restore();
            }
        }
    }

    void setUpRRects() {
        // each RRect must fit in a 0x0 -> (kTileX-2)x(kTileY-2) block. These will be tiled across
        // the screen in kTileX x kTileY tiles. The extra empty pixels on each side are for AA.

        // simple cases
        fRRects[0].setRect(SkRect::MakeWH(kTileX-2, kTileY-2));
        fRRects[1].setOval(SkRect::MakeWH(kTileX-2, kTileY-2));
        fRRects[2].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 10);

        // The first complex case needs special handling since it is a square
        fRRects[kNumSimpleCases].setRectRadii(SkRect::MakeWH(kTileY-2, kTileY-2), gRadii[0]);
        for (int i = 1; i < SK_ARRAY_COUNT(gRadii); ++i) {
            fRRects[kNumSimpleCases+i].setRectRadii(SkRect::MakeWH(kTileX-2, kTileY-2), gRadii[i]);
        }
    }

private:
    bool fDoAA;
    bool fDoClip;   // use clipRRect & drawRect instead of drawRRect

    static const int kImageWidth = 640;
    static const int kImageHeight = 480;

    static const int kTileX = 80;
    static const int kTileY = 40;

    static const int kNumSimpleCases = 3;
    static const int kNumComplexCases = 19;
    static const SkVector RRectGM::gRadii[kNumComplexCases][4];

    static const int kNumRRects = kNumSimpleCases + kNumComplexCases;
    SkRRect fRRects[kNumRRects];

    typedef GM INHERITED;
};

// Radii for the various test cases. Order is UL, UR, LR, LL
const SkVector RRectGM::gRadii[kNumComplexCases][4] = {
    // a circle
    { { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY } },

    // odd ball cases
    { { 8, 8 }, { 32, 32 }, { 8, 8 }, { 32, 32 } },
    { { 16, 8 }, { 8, 16 }, { 16, 8 }, { 8, 16 } },
    { { 0, 0 }, { 16, 16 }, { 8, 8 }, { 32, 32 } },

    // UL
    { { 30, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
    { { 30, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
    { { 15, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },

    // UR
    { { 0, 0 }, { 30, 30 }, { 0, 0 }, { 0, 0 } },
    { { 0, 0 }, { 30, 15 }, { 0, 0 }, { 0, 0 } },
    { { 0, 0 }, { 15, 30 }, { 0, 0 }, { 0, 0 } },

    // LR
    { { 0, 0 }, { 0, 0 }, { 30, 30 }, { 0, 0 } },
    { { 0, 0 }, { 0, 0 }, { 30, 15 }, { 0, 0 } },
    { { 0, 0 }, { 0, 0 }, { 15, 30 }, { 0, 0 } },

    // LL
    { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 30 } },
    { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 15 } },
    { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 30 } },

    // over-sized radii
    { { 0, 0 }, { 100, 400 }, { 0, 0 }, { 0, 0 } },
    { { 0, 0 }, { 400, 400 }, { 0, 0 }, { 0, 0 } },
    { { 400, 400 }, { 400, 400 }, { 400, 400 }, { 400, 400 } },
};

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

DEF_GM( return new RRectGM(false, false); )
DEF_GM( return new RRectGM(true, false); )
DEF_GM( return new RRectGM(false, true); )
DEF_GM( return new RRectGM(true, true); )

}

<commit_msg>Fix compiler warning-as-error issue<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkRRect.h"

namespace skiagm {

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

class RRectGM : public GM {
public:
    RRectGM(bool doAA, bool doClip) : fDoAA(doAA), fDoClip(doClip) {
        this->setBGColor(0xFFDDDDDD);
        this->setUpRRects();
    }

protected:
    SkString onShortName() {
        SkString name("rrect");
        if (fDoClip) {
            name.append("_clip");
        }
        if (fDoAA) {
            name.append("_aa");
        } else {
            name.append("_bw");
        }

        return name;
    }

    virtual SkISize onISize() { return make_isize(kImageWidth, kImageHeight); }

    virtual void onDraw(SkCanvas* canvas) {

        SkPaint paint;
        // when clipping the AA is pushed into the clip operation
        paint.setAntiAlias(fDoClip ? false : fDoAA);

        static const SkRect kMaxTileBound = SkRect::MakeWH(SkIntToScalar(kTileX), SkIntToScalar(kTileY));

        int curRRect = 0;
        for (int y = 1; y < kImageHeight; y += kTileY) {
            for (int x = 1; x < kImageWidth; x += kTileX) {
                if (curRRect >= kNumRRects) {
                    break;
                }
                SkASSERT(kMaxTileBound.contains(fRRects[curRRect].getBounds()));

                canvas->save();
                    canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
                    if (fDoClip) {
                        canvas->clipRRect(fRRects[curRRect], SkRegion::kReplace_Op, fDoAA);
                        canvas->drawRect(kMaxTileBound, paint);
                    } else {
                        canvas->drawRRect(fRRects[curRRect], paint);
                    }
                    ++curRRect;
                canvas->restore();
            }
        }
    }

    void setUpRRects() {
        // each RRect must fit in a 0x0 -> (kTileX-2)x(kTileY-2) block. These will be tiled across
        // the screen in kTileX x kTileY tiles. The extra empty pixels on each side are for AA.

        // simple cases
        fRRects[0].setRect(SkRect::MakeWH(kTileX-2, kTileY-2));
        fRRects[1].setOval(SkRect::MakeWH(kTileX-2, kTileY-2));
        fRRects[2].setRectXY(SkRect::MakeWH(kTileX-2, kTileY-2), 10, 10);

        // The first complex case needs special handling since it is a square
        fRRects[kNumSimpleCases].setRectRadii(SkRect::MakeWH(kTileY-2, kTileY-2), gRadii[0]);
        for (int i = 1; i < SK_ARRAY_COUNT(gRadii); ++i) {
            fRRects[kNumSimpleCases+i].setRectRadii(SkRect::MakeWH(kTileX-2, kTileY-2), gRadii[i]);
        }
    }

private:
    bool fDoAA;
    bool fDoClip;   // use clipRRect & drawRect instead of drawRRect

    static const int kImageWidth = 640;
    static const int kImageHeight = 480;

    static const int kTileX = 80;
    static const int kTileY = 40;

    static const int kNumSimpleCases = 3;
    static const int kNumComplexCases = 19;
    static const SkVector gRadii[kNumComplexCases][4];

    static const int kNumRRects = kNumSimpleCases + kNumComplexCases;
    SkRRect fRRects[kNumRRects];

    typedef GM INHERITED;
};

// Radii for the various test cases. Order is UL, UR, LR, LL
const SkVector RRectGM::gRadii[kNumComplexCases][4] = {
    // a circle
    { { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY }, { kTileY, kTileY } },

    // odd ball cases
    { { 8, 8 }, { 32, 32 }, { 8, 8 }, { 32, 32 } },
    { { 16, 8 }, { 8, 16 }, { 16, 8 }, { 8, 16 } },
    { { 0, 0 }, { 16, 16 }, { 8, 8 }, { 32, 32 } },

    // UL
    { { 30, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
    { { 30, 15 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },
    { { 15, 30 }, { 0, 0 }, { 0, 0 }, { 0, 0 } },

    // UR
    { { 0, 0 }, { 30, 30 }, { 0, 0 }, { 0, 0 } },
    { { 0, 0 }, { 30, 15 }, { 0, 0 }, { 0, 0 } },
    { { 0, 0 }, { 15, 30 }, { 0, 0 }, { 0, 0 } },

    // LR
    { { 0, 0 }, { 0, 0 }, { 30, 30 }, { 0, 0 } },
    { { 0, 0 }, { 0, 0 }, { 30, 15 }, { 0, 0 } },
    { { 0, 0 }, { 0, 0 }, { 15, 30 }, { 0, 0 } },

    // LL
    { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 30 } },
    { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 30, 15 } },
    { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 15, 30 } },

    // over-sized radii
    { { 0, 0 }, { 100, 400 }, { 0, 0 }, { 0, 0 } },
    { { 0, 0 }, { 400, 400 }, { 0, 0 }, { 0, 0 } },
    { { 400, 400 }, { 400, 400 }, { 400, 400 }, { 400, 400 } },
};

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

DEF_GM( return new RRectGM(false, false); )
DEF_GM( return new RRectGM(true, false); )
DEF_GM( return new RRectGM(false, true); )
DEF_GM( return new RRectGM(true, true); )

}

<|endoftext|>


<commit_before>/* Copyright (c) 2010-2012 Stanford University
 * Copyright (c) 2011 Facebook
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "CycleCounter.h"
#include "MembershipClient.h"
#include "ShortMacros.h"
#include "RawMetrics.h"
#include "ServiceManager.h"
#include "TransportManager.h"
#include "TransportFactory.h"
#include "TcpTransport.h"
#include "FastTransport.h"
#include "UdpDriver.h"
#include "FailSession.h"

#ifdef INFINIBAND
#include "InfRcTransport.h"
#include "InfUdDriver.h"
#endif

namespace RAMCloud {

static struct TcpTransportFactory : public TransportFactory {
    TcpTransportFactory()
        : TransportFactory("kernelTcp", "tcp") {}
    Transport* createTransport(Context& context,
            const ServiceLocator* localServiceLocator) {
        return new TcpTransport(context, localServiceLocator);
    }
} tcpTransportFactory;

static struct FastUdpTransportFactory : public TransportFactory {
    FastUdpTransportFactory()
        : TransportFactory("fast+kernelUdp", "fast+udp") {}
    Transport* createTransport(Context& context,
            const ServiceLocator* localServiceLocator) {
        return new FastTransport(context,
                new UdpDriver(context, localServiceLocator));
    }
} fastUdpTransportFactory;

#ifdef INFINIBAND
static struct FastInfUdTransportFactory : public TransportFactory {
    FastInfUdTransportFactory()
        : TransportFactory("fast+infinibandud", "fast+infud") {}
    Transport* createTransport(Context& context,
            const ServiceLocator* localServiceLocator) {
        return new FastTransport(context,
                new InfUdDriver<>(context, localServiceLocator, false));
    }
} fastInfUdTransportFactory;

static struct FastInfEthTransportFactory : public TransportFactory {
    FastInfEthTransportFactory()
        : TransportFactory("fast+infinibandethernet", "fast+infeth") {}
    Transport* createTransport(Context& context,
            const ServiceLocator* localServiceLocator) {
        return new FastTransport(context,
                new InfUdDriver<>(context, localServiceLocator, true));
    }
} fastInfEthTransportFactory;

static struct InfRcTransportFactory : public TransportFactory {
    InfRcTransportFactory()
        : TransportFactory("infinibandrc", "infrc") {}
    Transport* createTransport(Context& context,
            const ServiceLocator* localServiceLocator) {
        return new InfRcTransport<>(context, localServiceLocator);
    }
} infRcTransportFactory;
#endif

TransportManager::TransportManager(Context& context)
    : context(context)
    , isServer(false)
    , transportFactories()
    , transports()
    , listeningLocators()
    , sessionCache()
    , registeredBases()
    , registeredSizes()
    , mutex()
    , timeoutMs(0)
    , skipServerIdCheck(false)
{
    transportFactories.push_back(&tcpTransportFactory);
    transportFactories.push_back(&fastUdpTransportFactory);
#ifdef INFINIBAND
    transportFactories.push_back(&fastInfUdTransportFactory);
    transportFactories.push_back(&fastInfEthTransportFactory);
    transportFactories.push_back(&infRcTransportFactory);
#endif
    transports.resize(transportFactories.size(), NULL);
}

TransportManager::~TransportManager()
{
    // Must clear the cache and destroy sessionRefs before the
    // transports are destroyed.
    sessionCache.clear();
    foreach (auto transport, transports)
        delete transport;
}

/**
 * This method is invoked only on servers; it creates transport(s) that will be
 * used to receive RPC requests.  These transports can also be used for outgoing
 * RPC requests, and additional transports for outgoing requests will be
 * created on-demand by #getSession.
 *
 * \param localServiceLocator
 *      Specifies one or more locators that clients can use to send requests to
 *      this server.
 */
void
TransportManager::initialize(const char* localServiceLocator)
{
    isServer = true;
    Dispatch::Lock lock(context.dispatch);
    std::vector<ServiceLocator> locators =
            ServiceLocator::parseServiceLocators(localServiceLocator);

    if (locators.empty()) {
        throw Exception(HERE,
            "Servers must listen on at least one service locator, but "
            "none was provided");
    }

    uint32_t numListeningTransports = 0;
    foreach (auto& locator, locators) {
        for (uint32_t i = 0; i < transportFactories.size(); i++) {
            TransportFactory* factory = transportFactories[i];
            if (factory->supports(locator.getProtocol().c_str())) {
                // The transport supports a protocol that we can receive
                // requests on.
                Transport *transport = factory->createTransport(context,
                                                                &locator);
                for (uint32_t j = 0; j < registeredBases.size(); j++) {
                    transport->registerMemory(registeredBases[j],
                                              registeredSizes[j]);
                }
                if (transports[i] == NULL) {
                    transports[i] = transport;
                } else {
                    // If we get here, it means we've already created at
                    // least one transport for this factory.
                    transports.push_back(transport);
                }
                // Ask the transport for its service locator. This might be
                // more specific than "locator", as the transport may have
                // added information.
                string listeningLocator = transport->getServiceLocator();
                if (listeningLocator.empty()) {
                    throw Exception(HERE,
                        format("Listening transport has empty locator. "
                               "Was initialized with '%s'",
                               locator.getOriginalString().c_str()));
                }
                if (listeningLocators.size() != 0)
                    listeningLocators += ";";
                listeningLocators += listeningLocator;
                ++numListeningTransports;
                break;
            }
        }
    }
    if (numListeningTransports == 0) {
        dumpTransportFactories();
        throw Exception(HERE, format(
            "Servers must listen on at least one service locator, but no "
            "possible transports were found for '%s'", localServiceLocator));
    }
}

/**
 * Remove a session from the session cache, if it is present.
 *
 * \param serviceLocator
 *      Service locator for which any existing session should be flushed (was
 *      passed to an earlier call to getSession).
 */
void
TransportManager::flushSession(const char* serviceLocator)
{
    TEST_LOG("flushing session for %s", serviceLocator);
    auto it = sessionCache.find(serviceLocator);
    if (it != sessionCache.end())
        sessionCache.erase(it);
}

/**
 * Get a session on which to send RPC requests to a service.  This method
 * keeps a cache of sessions and will reuse existing sessions whenever
 * possible. If necessary, the method also instantiates new transports
 * based on the service locator.
 *
 * \param serviceLocator
 *      Desired service.
 *
 * \return
 *      A session corresponding to serviceLocator. If a session could not
 *      be opened for serviceLocator then the error gets logged and a
 *      FailSession is returned.
 *
 * \throw NoSuchKeyException
 *      A transport supporting one of the protocols claims a service locator
 *      option is missing.
 * \throw BadValueException
 *      A transport supporting one of the protocols claims a service locator
 *      option is malformed.
 */
Transport::SessionRef
TransportManager::getSession(const char* serviceLocator)
{
    // If we're running on a server (i.e., multithreaded) must exclude
    // other threads.
    Tub<std::lock_guard<SpinLock>> lock;
    if (isServer) {
        lock.construct(mutex);
    }

    // First check to see if we have already opened a session for the
    // locator; this should almost always be true.
    auto it = sessionCache.find(serviceLocator);
    if (it != sessionCache.end())
        return it->second;

    CycleCounter<RawMetric> counter;

    // Session was not found in the cache, so create a new one and add
    // it to the cache.
    Transport::SessionRef session(openSession(serviceLocator));
    if (session == FailSession::get()) {
        // This is temporary; eventually we should just return the FailSession.
        throw TransportException(HERE,
                format("Couldn't open session for locator %s",
                serviceLocator));
    }
    sessionCache.insert({serviceLocator, session});
    return session;
}

/**
 * Open a session based on a ServiceLocator string, but ensure that the
 * remote end is the expected ServerId. This will guarantee that the
 * session returned is to the precise server requested. Using locator
 * strings does not guarantee this, as they may be reused across different
 * process instantiations.
 *
 * \param serviceLocator
 *      Desired service.
 *
 * \param needServerId
 *      The ServerId expected for the server being connected to. If the
 *      given id does not match the other end an exception is thrown.
 *
 * \throw NoSuchKeyException
 *      A transport supporting one of the protocols claims a service locator
 *      option is missing.
 *
 * \throw BadValueException
 *      A transport supporting one of the protocols claims a service locator
 *      option is malformed.
 *
 * \throw TransportException
 *      No transport was found for this service locator, or the remote server's
 *      ServerId either could not be obtained or did not match the one provided.
 */
Transport::SessionRef
TransportManager::getSession(const char* serviceLocator, ServerId needServerId)
{
    Transport::SessionRef session = getSession(serviceLocator);
    ServerId actualId;

    if (skipServerIdCheck)
        return session;
    try {
        actualId = MembershipClient::getServerId(context, session);
    } catch (TransportException& e) {
        LOG(DEBUG, "Failed to obtain ServerId from \"%s\": %s",
            serviceLocator, e.what());
        // Fall through to error handling below (since actualId remains
        // invalid).
    }

    if (actualId != needServerId) {
        // Looks like a locator was reused before this ServerId was
        // removed. This is possible, but should be very rare.
        string errorStr = format("Expected ServerId %lu at \"%s\", but actual "
            "server id was %lu!",
            *needServerId, serviceLocator, *actualId);
        LOG(DEBUG, "%s", errorStr.c_str());
        throw TransportException(HERE, errorStr);
    }

    return session;
}

/**
 * Return a ServiceLocator string corresponding to the listening
 * ServiceLocators.
 * \return
 *      A semicolon-delimited, ServiceLocator string containing all
 *      ServiceLocators' strings that are listening to RPCs.
 */
string
TransportManager::getListeningLocatorsString()
{
    return listeningLocators;
}

/**
 * Given a service locator, open a new session connected to that service
 * locator.  If necessary, this method also instantiates a new transport
 * based on the service locator.  This method accesses no shared data, so
 * it is thread-safe.
 *
 * \param serviceLocator
 *      Desired service.
 *
 * \return
 *      A reference to the new session. If a session could not be opened,
 *      an error message is logged and the FailSession is returned.
 */
Transport::SessionRef
TransportManager::openSession(const char* serviceLocator)
{
    // Collects error messages from all the transports that tried to
    // open a session from this locator.
    string messages;

    // Iterate over all of the sub-locators, looking for a transport that
    // can handle its protocol.
    vector<ServiceLocator> locators =
            ServiceLocator::parseServiceLocators(serviceLocator);
    foreach (ServiceLocator& locator, locators) {
        for (uint32_t i = 0; i < transportFactories.size(); i++) {
            TransportFactory* factory = transportFactories[i];
            if (!factory->supports(locator.getProtocol().c_str())) {
                continue;
            }

            if (transports[i] == NULL) {
                // Try to create a new transport via this factory.
                // It's OK if that doesn't work (e.g. the particular
                // transport may depend on physical devices that don't
                // exist on this machine).
                try {
                    Dispatch::Lock lock(context.dispatch);
                    transports[i] = factory->createTransport(context, NULL);
                    for (uint32_t j = 0; j < registeredBases.size(); j++) {
                        transports[i]->registerMemory(registeredBases[j],
                                                      registeredSizes[j]);
                    }
                } catch (TransportException &e) {
                    continue;
                }
            }

            try {
                Transport::SessionRef session = transports[i]->getSession(
                        locator, timeoutMs);
                if (isServer) {
                    session = new ServiceManager::WorkerSession(context,
                                                                session);
                }
                session->setServiceLocator(serviceLocator);
                return session;
            } catch (TransportException& e) {
                // Save error information in case none of the locators works.
                if (locators.size() == 1) {
                    messages = e.message;
                } else {
                    if (!messages.empty()) {
                        messages += ", ";
                    }
                    messages += locator.getOriginalString().c_str();
                    messages += ": ";
                    messages += e.message;
                }
            }
        }
    }

    if (messages.empty()) {
        LOG(WARNING, "No supported transport found for locator %s",
                serviceLocator);
    } else {
        LOG(WARNING, "Couldn't open session for locator %s (%s)",
                serviceLocator, messages.c_str());
    }
    return FailSession::get();
}

/**
 * See #Transport::registerMemory.
 */
void
TransportManager::registerMemory(void* base, size_t bytes)
{
    Dispatch::Lock lock(context.dispatch);
    foreach (auto transport, transports) {
        if (transport != NULL)
            transport->registerMemory(base, bytes);
    }
    registeredBases.push_back(base);
    registeredSizes.push_back(bytes);
}

/**
 * Use a particular timeout value for all new transports created from now on.
 *
 * \param timeoutMs
 *      Timeout period (in ms) to pass to transports.
 */
void TransportManager::setTimeout(uint32_t timeoutMs)
{
    this->timeoutMs = timeoutMs;
}

/**
 * Calls dumpStats() on all existing transports.
 */
void
TransportManager::dumpStats()
{
    Dispatch::Lock lock(context.dispatch);
    foreach (auto transport, transports) {
        if (transport != NULL)
            transport->dumpStats();
    }
}

/**
 * Logs the list of transport factories and the protocols they support.
 */
void
TransportManager::dumpTransportFactories()
{
    Dispatch::Lock lock(context.dispatch);
    LOG(NOTICE, "The following transport factories are known:");
    uint32_t i = 0;
    foreach (auto factory, transportFactories) {
        LOG(NOTICE,
            "Transport factory %u supports the following protocols:", i);
        foreach (const char* protocol, factory->getProtocols())
          LOG(NOTICE, "  %s", protocol);
        ++i;
    }
}

} // namespace RAMCloud
<commit_msg>Temporary fix for session reuse problem.<commit_after>/* Copyright (c) 2010-2012 Stanford University
 * Copyright (c) 2011 Facebook
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "CycleCounter.h"
#include "MembershipClient.h"
#include "ShortMacros.h"
#include "RawMetrics.h"
#include "ServiceManager.h"
#include "TransportManager.h"
#include "TransportFactory.h"
#include "TcpTransport.h"
#include "FastTransport.h"
#include "UdpDriver.h"
#include "FailSession.h"

#ifdef INFINIBAND
#include "InfRcTransport.h"
#include "InfUdDriver.h"
#endif

namespace RAMCloud {

static struct TcpTransportFactory : public TransportFactory {
    TcpTransportFactory()
        : TransportFactory("kernelTcp", "tcp") {}
    Transport* createTransport(Context& context,
            const ServiceLocator* localServiceLocator) {
        return new TcpTransport(context, localServiceLocator);
    }
} tcpTransportFactory;

static struct FastUdpTransportFactory : public TransportFactory {
    FastUdpTransportFactory()
        : TransportFactory("fast+kernelUdp", "fast+udp") {}
    Transport* createTransport(Context& context,
            const ServiceLocator* localServiceLocator) {
        return new FastTransport(context,
                new UdpDriver(context, localServiceLocator));
    }
} fastUdpTransportFactory;

#ifdef INFINIBAND
static struct FastInfUdTransportFactory : public TransportFactory {
    FastInfUdTransportFactory()
        : TransportFactory("fast+infinibandud", "fast+infud") {}
    Transport* createTransport(Context& context,
            const ServiceLocator* localServiceLocator) {
        return new FastTransport(context,
                new InfUdDriver<>(context, localServiceLocator, false));
    }
} fastInfUdTransportFactory;

static struct FastInfEthTransportFactory : public TransportFactory {
    FastInfEthTransportFactory()
        : TransportFactory("fast+infinibandethernet", "fast+infeth") {}
    Transport* createTransport(Context& context,
            const ServiceLocator* localServiceLocator) {
        return new FastTransport(context,
                new InfUdDriver<>(context, localServiceLocator, true));
    }
} fastInfEthTransportFactory;

static struct InfRcTransportFactory : public TransportFactory {
    InfRcTransportFactory()
        : TransportFactory("infinibandrc", "infrc") {}
    Transport* createTransport(Context& context,
            const ServiceLocator* localServiceLocator) {
        return new InfRcTransport<>(context, localServiceLocator);
    }
} infRcTransportFactory;
#endif

TransportManager::TransportManager(Context& context)
    : context(context)
    , isServer(false)
    , transportFactories()
    , transports()
    , listeningLocators()
    , sessionCache()
    , registeredBases()
    , registeredSizes()
    , mutex()
    , timeoutMs(0)
    , skipServerIdCheck(false)
{
    transportFactories.push_back(&tcpTransportFactory);
    transportFactories.push_back(&fastUdpTransportFactory);
#ifdef INFINIBAND
    transportFactories.push_back(&fastInfUdTransportFactory);
    transportFactories.push_back(&fastInfEthTransportFactory);
    transportFactories.push_back(&infRcTransportFactory);
#endif
    transports.resize(transportFactories.size(), NULL);
}

TransportManager::~TransportManager()
{
    // Must clear the cache and destroy sessionRefs before the
    // transports are destroyed.
    sessionCache.clear();
    foreach (auto transport, transports)
        delete transport;
}

/**
 * This method is invoked only on servers; it creates transport(s) that will be
 * used to receive RPC requests.  These transports can also be used for outgoing
 * RPC requests, and additional transports for outgoing requests will be
 * created on-demand by #getSession.
 *
 * \param localServiceLocator
 *      Specifies one or more locators that clients can use to send requests to
 *      this server.
 */
void
TransportManager::initialize(const char* localServiceLocator)
{
    isServer = true;
    Dispatch::Lock lock(context.dispatch);
    std::vector<ServiceLocator> locators =
            ServiceLocator::parseServiceLocators(localServiceLocator);

    if (locators.empty()) {
        throw Exception(HERE,
            "Servers must listen on at least one service locator, but "
            "none was provided");
    }

    uint32_t numListeningTransports = 0;
    foreach (auto& locator, locators) {
        for (uint32_t i = 0; i < transportFactories.size(); i++) {
            TransportFactory* factory = transportFactories[i];
            if (factory->supports(locator.getProtocol().c_str())) {
                // The transport supports a protocol that we can receive
                // requests on.
                Transport *transport = factory->createTransport(context,
                                                                &locator);
                for (uint32_t j = 0; j < registeredBases.size(); j++) {
                    transport->registerMemory(registeredBases[j],
                                              registeredSizes[j]);
                }
                if (transports[i] == NULL) {
                    transports[i] = transport;
                } else {
                    // If we get here, it means we've already created at
                    // least one transport for this factory.
                    transports.push_back(transport);
                }
                // Ask the transport for its service locator. This might be
                // more specific than "locator", as the transport may have
                // added information.
                string listeningLocator = transport->getServiceLocator();
                if (listeningLocator.empty()) {
                    throw Exception(HERE,
                        format("Listening transport has empty locator. "
                               "Was initialized with '%s'",
                               locator.getOriginalString().c_str()));
                }
                if (listeningLocators.size() != 0)
                    listeningLocators += ";";
                listeningLocators += listeningLocator;
                ++numListeningTransports;
                break;
            }
        }
    }
    if (numListeningTransports == 0) {
        dumpTransportFactories();
        throw Exception(HERE, format(
            "Servers must listen on at least one service locator, but no "
            "possible transports were found for '%s'", localServiceLocator));
    }
}

/**
 * Remove a session from the session cache, if it is present.
 *
 * \param serviceLocator
 *      Service locator for which any existing session should be flushed (was
 *      passed to an earlier call to getSession).
 */
void
TransportManager::flushSession(const char* serviceLocator)
{
    TEST_LOG("flushing session for %s", serviceLocator);
    auto it = sessionCache.find(serviceLocator);
    if (it != sessionCache.end())
        sessionCache.erase(it);
}

/**
 * Get a session on which to send RPC requests to a service.  This method
 * keeps a cache of sessions and will reuse existing sessions whenever
 * possible. If necessary, the method also instantiates new transports
 * based on the service locator.
 *
 * \param serviceLocator
 *      Desired service.
 *
 * \return
 *      A session corresponding to serviceLocator. If a session could not
 *      be opened for serviceLocator then the error gets logged and a
 *      FailSession is returned.
 *
 * \throw NoSuchKeyException
 *      A transport supporting one of the protocols claims a service locator
 *      option is missing.
 * \throw BadValueException
 *      A transport supporting one of the protocols claims a service locator
 *      option is malformed.
 */
Transport::SessionRef
TransportManager::getSession(const char* serviceLocator)
{
    // If we're running on a server (i.e., multithreaded) must exclude
    // other threads.
    Tub<std::lock_guard<SpinLock>> lock;
    if (isServer) {
        lock.construct(mutex);
    }

    // First check to see if we have already opened a session for the
    // locator; this should almost always be true.
    auto it = sessionCache.find(serviceLocator);
    if (it != sessionCache.end())
        return it->second;

    CycleCounter<RawMetric> counter;

    // Session was not found in the cache, so create a new one and add
    // it to the cache.
    Transport::SessionRef session(openSession(serviceLocator));
    if (session == FailSession::get()) {
        // This is temporary; eventually we should just return the FailSession.
        throw TransportException(HERE,
                format("Couldn't open session for locator %s",
                serviceLocator));
    }
    sessionCache.insert({serviceLocator, session});
    return session;
}

/**
 * Open a session based on a ServiceLocator string, but ensure that the
 * remote end is the expected ServerId. This will guarantee that the
 * session returned is to the precise server requested. Using locator
 * strings does not guarantee this, as they may be reused across different
 * process instantiations.
 *
 * \param serviceLocator
 *      Desired service.
 *
 * \param needServerId
 *      The ServerId expected for the server being connected to. If the
 *      given id does not match the other end an exception is thrown.
 *
 * \throw NoSuchKeyException
 *      A transport supporting one of the protocols claims a service locator
 *      option is missing.
 *
 * \throw BadValueException
 *      A transport supporting one of the protocols claims a service locator
 *      option is malformed.
 *
 * \throw TransportException
 *      No transport was found for this service locator, or the remote server's
 *      ServerId either could not be obtained or did not match the one provided.
 */
Transport::SessionRef
TransportManager::getSession(const char* serviceLocator, ServerId needServerId)
{
    Transport::SessionRef session = getSession(serviceLocator);
    ServerId actualId;

    if (skipServerIdCheck)
        return session;
    try {
        actualId = MembershipClient::getServerId(context, session);
    } catch (TransportException& e) {
        LOG(DEBUG, "Failed to obtain ServerId from \"%s\": %s",
            serviceLocator, e.what());
        flushSession(serviceLocator);
        // Fall through to error handling below (since actualId remains
        // invalid).
    }

    if (actualId != needServerId) {
        // Looks like a locator was reused before this ServerId was
        // removed. This is possible, but should be very rare.
        string errorStr = format("Expected ServerId %lu at \"%s\", but actual "
            "server id was %lu!",
            *needServerId, serviceLocator, *actualId);
        flushSession(serviceLocator);
        LOG(DEBUG, "%s", errorStr.c_str());
        throw TransportException(HERE, errorStr);
    }

    return session;
}

/**
 * Return a ServiceLocator string corresponding to the listening
 * ServiceLocators.
 * \return
 *      A semicolon-delimited, ServiceLocator string containing all
 *      ServiceLocators' strings that are listening to RPCs.
 */
string
TransportManager::getListeningLocatorsString()
{
    return listeningLocators;
}

/**
 * Given a service locator, open a new session connected to that service
 * locator.  If necessary, this method also instantiates a new transport
 * based on the service locator.  This method accesses no shared data, so
 * it is thread-safe.
 *
 * \param serviceLocator
 *      Desired service.
 *
 * \return
 *      A reference to the new session. If a session could not be opened,
 *      an error message is logged and the FailSession is returned.
 */
Transport::SessionRef
TransportManager::openSession(const char* serviceLocator)
{
    // Collects error messages from all the transports that tried to
    // open a session from this locator.
    string messages;

    // Iterate over all of the sub-locators, looking for a transport that
    // can handle its protocol.
    vector<ServiceLocator> locators =
            ServiceLocator::parseServiceLocators(serviceLocator);
    foreach (ServiceLocator& locator, locators) {
        for (uint32_t i = 0; i < transportFactories.size(); i++) {
            TransportFactory* factory = transportFactories[i];
            if (!factory->supports(locator.getProtocol().c_str())) {
                continue;
            }

            if (transports[i] == NULL) {
                // Try to create a new transport via this factory.
                // It's OK if that doesn't work (e.g. the particular
                // transport may depend on physical devices that don't
                // exist on this machine).
                try {
                    Dispatch::Lock lock(context.dispatch);
                    transports[i] = factory->createTransport(context, NULL);
                    for (uint32_t j = 0; j < registeredBases.size(); j++) {
                        transports[i]->registerMemory(registeredBases[j],
                                                      registeredSizes[j]);
                    }
                } catch (TransportException &e) {
                    continue;
                }
            }

            try {
                Transport::SessionRef session = transports[i]->getSession(
                        locator, timeoutMs);
                if (isServer) {
                    session = new ServiceManager::WorkerSession(context,
                                                                session);
                }
                session->setServiceLocator(serviceLocator);
                return session;
            } catch (TransportException& e) {
                // Save error information in case none of the locators works.
                if (locators.size() == 1) {
                    messages = e.message;
                } else {
                    if (!messages.empty()) {
                        messages += ", ";
                    }
                    messages += locator.getOriginalString().c_str();
                    messages += ": ";
                    messages += e.message;
                }
            }
        }
    }

    if (messages.empty()) {
        LOG(WARNING, "No supported transport found for locator %s",
                serviceLocator);
    } else {
        LOG(WARNING, "Couldn't open session for locator %s (%s)",
                serviceLocator, messages.c_str());
    }
    return FailSession::get();
}

/**
 * See #Transport::registerMemory.
 */
void
TransportManager::registerMemory(void* base, size_t bytes)
{
    Dispatch::Lock lock(context.dispatch);
    foreach (auto transport, transports) {
        if (transport != NULL)
            transport->registerMemory(base, bytes);
    }
    registeredBases.push_back(base);
    registeredSizes.push_back(bytes);
}

/**
 * Use a particular timeout value for all new transports created from now on.
 *
 * \param timeoutMs
 *      Timeout period (in ms) to pass to transports.
 */
void TransportManager::setTimeout(uint32_t timeoutMs)
{
    this->timeoutMs = timeoutMs;
}

/**
 * Calls dumpStats() on all existing transports.
 */
void
TransportManager::dumpStats()
{
    Dispatch::Lock lock(context.dispatch);
    foreach (auto transport, transports) {
        if (transport != NULL)
            transport->dumpStats();
    }
}

/**
 * Logs the list of transport factories and the protocols they support.
 */
void
TransportManager::dumpTransportFactories()
{
    Dispatch::Lock lock(context.dispatch);
    LOG(NOTICE, "The following transport factories are known:");
    uint32_t i = 0;
    foreach (auto factory, transportFactories) {
        LOG(NOTICE,
            "Transport factory %u supports the following protocols:", i);
        foreach (const char* protocol, factory->getProtocols())
          LOG(NOTICE, "  %s", protocol);
        ++i;
    }
}

} // namespace RAMCloud
<|endoftext|>


<commit_before>#ifndef DATA_TYPE_HPP
#define DATA_TYPE_HPP

#include <string>
#include <list>

// applying namespace to avoid naming conflicts, thanks
// NOTE: please add following line if you are using these types
/*
using namespace utls;
*/
namespace utls {

    enum Operator {EQUAL, UNEQUAL, LESS, MORE, NO_MORE, NO_LESS, TOTAL_OPERATOR};

    enum DataType {INT, FLOAT, CHAR, TOTAL_TYPE};

}

typedef struct AttributeType {
    utls::DataType type;
    void *dataPtr;
} Attribute;

typedef std::list < Attribute > Entry;
typedef std::list < Entry > Entries;

struct DataAddr {
    std::string filename;
    unsigned int dataaddr;
    unsigned int datalen;
};

typedef struct SchemeType {
private:
    std::string name;
    utls::DataType dataType;
    int charLength;
    bool indexed;
public:
    void setName(const std::string &name);
    void setDataType(const utls::DataType &dataType);
    void setCharLength(const int &charLength);

    std::string getName();
    utls::DataType getDataType();
    int getCharLength();
    bool getIndexed();
} Scheme;

typedef std::list < Scheme > TableDefinition;

utls::DataType getDataType(const TableDefinition& td, const std::string attName) {
    for (const std::list <Scheme>::iterator &i = td.begin(); i != td.end(); ++i) {
        if (i->name == attName)
            return i->dataType;
    }
    return utls::TOTAL_TYPE;
}

class Condition {
private:
    std::string key;
    utls::Operator op;
    void *valuePtr;

public:
    void setKey(const std::string &key);
    void setOp(const utls::Operator &op);
    void setValue(const void *valuePtr);

    std::string getKey();
    utls::Operator getOp();
    void *getValuePtr();
};

#endif
<commit_msg>workaround: comment out something<commit_after>#ifndef DATA_TYPE_HPP
#define DATA_TYPE_HPP

#include <string>
#include <list>

// applying namespace to avoid naming conflicts, thanks
// NOTE: please add following line if you are using these types
/*
using namespace utls;
*/
namespace utls {

    enum Operator {EQUAL, UNEQUAL, LESS, MORE, NO_MORE, NO_LESS, TOTAL_OPERATOR};

    enum DataType {INT, FLOAT, CHAR, TOTAL_TYPE};

}

typedef struct AttributeType {
    utls::DataType type;
    void *dataPtr;
} Attribute;

typedef std::list < Attribute > Entry;
typedef std::list < Entry > Entries;

struct DataAddr {
    std::string filename;
    unsigned int dataaddr;
    unsigned int datalen;
};

typedef struct SchemeType {

public: //TODO: change to private
    std::string name;
    utls::DataType dataType;
    int charLength;
    bool indexed;
public:
    void setName(const std::string &name);
    void setDataType(const utls::DataType &dataType);
    void setCharLength(const int &charLength);

    std::string getName();
    utls::DataType getDataType();
    int getCharLength();
    bool getIndexed();
} Scheme;

typedef std::list < Scheme > TableDefinition;

utls::DataType getDataType(const TableDefinition& td, const std::string attName) {
    /*
    for (const std::list <Scheme>::iterator i = td.begin(); i != td.end(); ++i) {
        if (i->name == attName)
            return i->dataType;
    }
    */
    return utls::TOTAL_TYPE;
}

class Condition {
private:
    std::string key;
    utls::Operator op;
    void *valuePtr;

public:
    void setKey(const std::string &key);
    void setOp(const utls::Operator &op);
    void setValue(const void *valuePtr);

    std::string getKey();
    utls::Operator getOp();
    void *getValuePtr();
};

#endif
<|endoftext|>


<commit_before>#include "VideoCaptureWrap.h"
#include "Matrix.h"
#include "OpenCV.h"

#include  <iostream>
using namespace std;

void AsyncRead(uv_work_t *req);
void AfterAsyncRead(uv_work_t *req);

v8::Persistent<FunctionTemplate> VideoCaptureWrap::constructor;

struct videocapture_baton {

	Persistent<Function> cb;
	VideoCaptureWrap *vc;
	Matrix *im;

	uv_work_t request;
};

void
VideoCaptureWrap::Init(Handle<Object> target) {
    HandleScope scope;

	// Constructor
	constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(VideoCaptureWrap::New));
	constructor->InstanceTemplate()->SetInternalFieldCount(1);
	constructor->SetClassName(String::NewSymbol("VideoCapture"));

	// Prototype
	//Local<ObjectTemplate> proto = constructor->PrototypeTemplate();

	NODE_SET_PROTOTYPE_METHOD(constructor, "read", Read);
	NODE_SET_PROTOTYPE_METHOD(constructor, "setWidth", SetWidth);
	NODE_SET_PROTOTYPE_METHOD(constructor, "setHeight", SetHeight);
	NODE_SET_PROTOTYPE_METHOD(constructor, "setPosition", SetPosition);

	target->Set(String::NewSymbol("VideoCapture"), constructor->GetFunction());
};

Handle<Value>
VideoCaptureWrap::New(const Arguments &args) {
	HandleScope scope;

  if (args.This()->InternalFieldCount() == 0)
		return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot Instantiate without new")));

	VideoCaptureWrap *v;

	if (args[0]->IsNumber()){
		v = new VideoCaptureWrap(args[0]->NumberValue());
	} else {
    //TODO - assumes that we have string, verify
    v = new VideoCaptureWrap(std::string(*v8::String::AsciiValue(args[0]->ToString())));
  }

	v->Wrap(args.This());

	return args.This();
}

VideoCaptureWrap::VideoCaptureWrap(int device){

	HandleScope scope;
	cap.open(device);

	if(!cap.isOpened()){
    v8::ThrowException(v8::Exception::Error(String::New("Camera could not be opened")));
	}
}

VideoCaptureWrap::VideoCaptureWrap(const std::string& filename){
  HandleScope scope;
	cap.open(filename);
  // TODO! At the moment this only takes a full path - do relative too.
	if(!cap.isOpened()){
    v8::ThrowException(v8::Exception::Error(String::New("Video file could not be opened (opencv reqs. non relative paths)")));
	}

}

Handle<Value>
VideoCaptureWrap::SetWidth(const Arguments &args){

	HandleScope scope;
	VideoCaptureWrap *v = ObjectWrap::Unwrap<VideoCaptureWrap>(args.This());

	if(args.Length() != 1)
		return scope.Close(Undefined());

	int w = args[0]->IntegerValue();

	if(v->cap.isOpened())
		v->cap.set(CV_CAP_PROP_FRAME_WIDTH, w);

	return scope.Close(Undefined());
}

Handle<Value>
VideoCaptureWrap::SetHeight(const Arguments &args){

	HandleScope scope;
	VideoCaptureWrap *v = ObjectWrap::Unwrap<VideoCaptureWrap>(args.This());

	if(args.Length() != 1)
		return scope.Close(Undefined());

	int h = args[0]->IntegerValue();

	v->cap.set(CV_CAP_PROP_FRAME_HEIGHT, h);

	return Undefined();
}

Handle<Value>
VideoCaptureWrap::SetPosition(const Arguments &args){

	HandleScope scope;
	VideoCaptureWrap *v = ObjectWrap::Unwrap<VideoCaptureWrap>(args.This());

	if(args.Length() != 1)
		return scope.Close(Undefined());

	int pos = args[0]->IntegerValue();

	v->cap.set(CV_CAP_PROP_POS_FRAMES, pos);

	return Undefined();
}

Handle<Value>
VideoCaptureWrap::Read(const Arguments &args) {

	HandleScope scope;
	VideoCaptureWrap *v = ObjectWrap::Unwrap<VideoCaptureWrap>(args.This());

	REQ_FUN_ARG(0, cb);

	videocapture_baton *baton = new videocapture_baton();
	baton->vc = v;
	baton->cb = Persistent<Function>::New(cb);
	baton->im = new Matrix();
	baton->request.data = baton;

	uv_queue_work(uv_default_loop(), &baton->request, AsyncRead,  (uv_after_work_cb)AfterAsyncRead);
	return Undefined();

}

void AsyncRead(uv_work_t *req) {
	videocapture_baton *baton = static_cast<videocapture_baton *>(req->data);

	baton->vc->cap.read(baton->im->mat);
}

void AfterAsyncRead(uv_work_t *req) {

	HandleScope scope;

	videocapture_baton *baton = static_cast<videocapture_baton *>(req->data);

	Local<Object> im_to_return= Matrix::constructor->GetFunction()->NewInstance();
	Matrix *img = ObjectWrap::Unwrap<Matrix>(im_to_return);
	cv::Mat mat;
	mat = baton->im->mat;

	img->mat = mat;
	Local<Value> argv[2];

  argv[0] = Local<Value>::New(Null());
	argv[1] = im_to_return;

	baton->cb->Call(Context::GetCurrent()->Global(), 2, argv);
	baton->cb.Dispose();

		delete baton;

}
<commit_msg>Added a delete for the matrix - Issue 101<commit_after>#include "VideoCaptureWrap.h"
#include "Matrix.h"
#include "OpenCV.h"

#include  <iostream>
using namespace std;

void AsyncRead(uv_work_t *req);
void AfterAsyncRead(uv_work_t *req);

v8::Persistent<FunctionTemplate> VideoCaptureWrap::constructor;

struct videocapture_baton {

	Persistent<Function> cb;
	VideoCaptureWrap *vc;
	Matrix *im;

	uv_work_t request;
};

void
VideoCaptureWrap::Init(Handle<Object> target) {
    HandleScope scope;

	// Constructor
	constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(VideoCaptureWrap::New));
	constructor->InstanceTemplate()->SetInternalFieldCount(1);
	constructor->SetClassName(String::NewSymbol("VideoCapture"));

	// Prototype
	//Local<ObjectTemplate> proto = constructor->PrototypeTemplate();

	NODE_SET_PROTOTYPE_METHOD(constructor, "read", Read);
	NODE_SET_PROTOTYPE_METHOD(constructor, "setWidth", SetWidth);
	NODE_SET_PROTOTYPE_METHOD(constructor, "setHeight", SetHeight);
	NODE_SET_PROTOTYPE_METHOD(constructor, "setPosition", SetPosition);

	target->Set(String::NewSymbol("VideoCapture"), constructor->GetFunction());
};

Handle<Value>
VideoCaptureWrap::New(const Arguments &args) {
	HandleScope scope;

  if (args.This()->InternalFieldCount() == 0)
		return v8::ThrowException(v8::Exception::TypeError(v8::String::New("Cannot Instantiate without new")));

	VideoCaptureWrap *v;

	if (args[0]->IsNumber()){
		v = new VideoCaptureWrap(args[0]->NumberValue());
	} else {
    //TODO - assumes that we have string, verify
    v = new VideoCaptureWrap(std::string(*v8::String::AsciiValue(args[0]->ToString())));
  }

	v->Wrap(args.This());

	return args.This();
}

VideoCaptureWrap::VideoCaptureWrap(int device){

	HandleScope scope;
	cap.open(device);

	if(!cap.isOpened()){
    v8::ThrowException(v8::Exception::Error(String::New("Camera could not be opened")));
	}
}

VideoCaptureWrap::VideoCaptureWrap(const std::string& filename){
  HandleScope scope;
	cap.open(filename);
  // TODO! At the moment this only takes a full path - do relative too.
	if(!cap.isOpened()){
    v8::ThrowException(v8::Exception::Error(String::New("Video file could not be opened (opencv reqs. non relative paths)")));
	}

}

Handle<Value>
VideoCaptureWrap::SetWidth(const Arguments &args){

	HandleScope scope;
	VideoCaptureWrap *v = ObjectWrap::Unwrap<VideoCaptureWrap>(args.This());

	if(args.Length() != 1)
		return scope.Close(Undefined());

	int w = args[0]->IntegerValue();

	if(v->cap.isOpened())
		v->cap.set(CV_CAP_PROP_FRAME_WIDTH, w);

	return scope.Close(Undefined());
}

Handle<Value>
VideoCaptureWrap::SetHeight(const Arguments &args){

	HandleScope scope;
	VideoCaptureWrap *v = ObjectWrap::Unwrap<VideoCaptureWrap>(args.This());

	if(args.Length() != 1)
		return scope.Close(Undefined());

	int h = args[0]->IntegerValue();

	v->cap.set(CV_CAP_PROP_FRAME_HEIGHT, h);

	return Undefined();
}

Handle<Value>
VideoCaptureWrap::SetPosition(const Arguments &args){

	HandleScope scope;
	VideoCaptureWrap *v = ObjectWrap::Unwrap<VideoCaptureWrap>(args.This());

	if(args.Length() != 1)
		return scope.Close(Undefined());

	int pos = args[0]->IntegerValue();

	v->cap.set(CV_CAP_PROP_POS_FRAMES, pos);

	return Undefined();
}

Handle<Value>
VideoCaptureWrap::Read(const Arguments &args) {

	HandleScope scope;
	VideoCaptureWrap *v = ObjectWrap::Unwrap<VideoCaptureWrap>(args.This());

	REQ_FUN_ARG(0, cb);

	videocapture_baton *baton = new videocapture_baton();
	baton->vc = v;
	baton->cb = Persistent<Function>::New(cb);
	baton->im = new Matrix();
	baton->request.data = baton;

	uv_queue_work(uv_default_loop(), &baton->request, AsyncRead,  (uv_after_work_cb)AfterAsyncRead);
	return Undefined();

}

void AsyncRead(uv_work_t *req) {
	videocapture_baton *baton = static_cast<videocapture_baton *>(req->data);

	baton->vc->cap.read(baton->im->mat);
}

void AfterAsyncRead(uv_work_t *req) {

	HandleScope scope;

	videocapture_baton *baton = static_cast<videocapture_baton *>(req->data);

	Local<Object> im_to_return= Matrix::constructor->GetFunction()->NewInstance();
	Matrix *img = ObjectWrap::Unwrap<Matrix>(im_to_return);
	cv::Mat mat;
	mat = baton->im->mat;

	img->mat = mat;
	Local<Value> argv[2];

  argv[0] = Local<Value>::New(Null());
	argv[1] = im_to_return;

	baton->cb->Call(Context::GetCurrent()->Global(), 2, argv);
	baton->cb.Dispose();

		delete baton->im;
		delete baton;

}
<|endoftext|>


<commit_before>
// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2014 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// 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 GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

#include "config.h"

#include <cassert>
#include <iostream>

#include "BaseType.h"
#include "Array.h"
#include "Byte.h"
#include "Int8.h"
#include "UInt16.h"
#include "Int16.h"
#include "UInt32.h"
#include "Int32.h"
#include "UInt64.h"
#include "Int64.h"
#include "Float32.h"
#include "Float64.h"
#include "Str.h"

#include "D4RValue.h"
#include "InternalErr.h"

#include "dods-datatypes.h"
#include "dods-limits.h"
#include "util.h"

using namespace std;

namespace libdap {

D4RValueList::~D4RValueList()
{
	for (std::vector<D4RValue *>::iterator i = d_rvalues.begin(), e = d_rvalues.end(); i != e; ++i)
		delete *i;
}

template<typename t, class DAP_TYPE>
static BaseType *
build_constant_array(vector<t> &values, DAP_TYPE &dt)
{
    Array *array = new Array("", &dt);
    array->append_dim(values.size());

    // TODO Make set_value_nocopy() methods so that values' pointers can be copied
    // instead of allocating memory twice. jhrg 7/5/13

    array->set_value(values, values.size());

    array->set_read_p(true);

    static unsigned long counter = 1;
    array->set_name(string("g") + long_to_string(counter++));

    return array;
}

D4RValue::D4RValue(unsigned long long ull) : d_variable(0), d_func(0), d_args(0), d_constant(0), d_value_kind(constant)
{
	UInt64 *ui = new UInt64("constant");
	ui->set_value(ull);
	d_constant = ui;
}

D4RValue::D4RValue(long long ll) : d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Int64 *i = new Int64("constant");
	i->set_value(ll);
	d_constant = i;
}

D4RValue::D4RValue(double r) : d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Float64 *f = new Float64("constant");
	f->set_value(r);
	d_constant = f;
}

D4RValue::D4RValue(std::string cpps) : d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Str *s = new Str("constant");
	s->set_value(cpps);
	d_constant = s;
}

D4RValue::D4RValue(std::vector<dods_byte> &byte_args)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Byte b("");
	d_constant = build_constant_array(byte_args, b);
}

D4RValue::D4RValue(std::vector<dods_int8> &byte_int8)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Int8 b("");
	d_constant = build_constant_array(byte_int8, b);
}

D4RValue::D4RValue(std::vector<dods_uint16> &byte_uint16)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	UInt16 b("");
	d_constant = build_constant_array(byte_uint16, b);
}

D4RValue::D4RValue(std::vector<dods_int16> &byte_int16)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Int16 b("");
	d_constant = build_constant_array(byte_int16, b);
}

D4RValue::D4RValue(std::vector<dods_uint32> &byte_uint32)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	UInt32 b("");
	d_constant = build_constant_array(byte_uint32, b);
}

D4RValue::D4RValue(std::vector<dods_int32> &byte_int32)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Int32 b("");
	d_constant = build_constant_array(byte_int32, b);
}

D4RValue::D4RValue(std::vector<dods_uint64> &byte_uint64)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	UInt64 b("");
	d_constant = build_constant_array(byte_uint64, b);
}

D4RValue::D4RValue(std::vector<dods_int64> &byte_int64)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Int64 b("");
	d_constant = build_constant_array(byte_int64, b);
}

D4RValue::D4RValue(std::vector<dods_float32> &byte_float32)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Float32 b("");
	d_constant = build_constant_array(byte_float32, b);
}

D4RValue::D4RValue(std::vector<dods_float64> &byte_float64)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Float64 b("");
	d_constant = build_constant_array(byte_float64, b);
}

D4RValue::~D4RValue() {
	// d_variable and d_func are weak pointers; don't delete.
	delete d_args;
	delete d_constant;
}

/** Return the BaseType * for a given RValue.
 *
 * @note A lingering issue with server functions is: Who or what is responsible
 * for deleting the BaseType* this method returns? Copying the BaseType wastes
 * memory but not copying it creates ambiguity since the BaseType* may point into
 * the DMR adn thus should not be freed or it might be newly allocated storage
 * (in which case it should). For the function result, we have no way of knowing
 * how/if to dispose of the BaseType*. Sort this out ... (reference counting,
 * mark and sweep, ...). Maybe duplicate it before it contains data? Then it can be
 * deleted without affecting the DMR
 * jhrg 3/10/14
 *
 * @param dmr The DMR to pass to a function.
 * @return A BaseType* that holds the value.
 */
BaseType *
D4RValue::value(DMR &dmr)
{
	switch (d_value_kind) {
	case basetype:
		d_variable->read();
		d_variable->set_read_p(true);
		return d_variable;

	case function: {
		return (*d_func)(d_args, dmr);
	}

	case constant:
		return d_constant;

	default:
		throw InternalErr(__FILE__, __LINE__, "Unknown rvalue type.");
	};
}

} // namespace libdap

<commit_msg>Comments and changed template type from 't' to 'T'.<commit_after>
// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2014 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// 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 GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

#include "config.h"

#include <cassert>
#include <iostream>

#include "BaseType.h"
#include "Array.h"
#include "Byte.h"
#include "Int8.h"
#include "UInt16.h"
#include "Int16.h"
#include "UInt32.h"
#include "Int32.h"
#include "UInt64.h"
#include "Int64.h"
#include "Float32.h"
#include "Float64.h"
#include "Str.h"

#include "D4RValue.h"
#include "InternalErr.h"

#include "dods-datatypes.h"
#include "dods-limits.h"
#include "util.h"

using namespace std;

namespace libdap {

D4RValueList::~D4RValueList()
{
	for (std::vector<D4RValue *>::iterator i = d_rvalues.begin(), e = d_rvalues.end(); i != e; ++i)
		delete *i;
}

template<typename T, class DAP_TYPE>
static BaseType *
build_constant_array(vector<T> &values, DAP_TYPE &dt)
{
    Array *array = new Array("", &dt);
    array->append_dim(values.size());

    // TODO Make set_value_nocopy() methods so that values' pointers can be copied
    // instead of allocating memory twice. jhrg 7/5/13

    array->set_value(values, values.size());

    array->set_read_p(true);

    static unsigned long counter = 1;
    array->set_name(string("g") + long_to_string(counter++));

    return array;
}

D4RValue::D4RValue(unsigned long long ull) : d_variable(0), d_func(0), d_args(0), d_constant(0), d_value_kind(constant)
{
	UInt64 *ui = new UInt64("constant");
	ui->set_value(ull);
	d_constant = ui;
}

D4RValue::D4RValue(long long ll) : d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Int64 *i = new Int64("constant");
	i->set_value(ll);
	d_constant = i;
}

D4RValue::D4RValue(double r) : d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Float64 *f = new Float64("constant");
	f->set_value(r);
	d_constant = f;
}

D4RValue::D4RValue(std::string cpps) : d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Str *s = new Str("constant");
	s->set_value(cpps);
	d_constant = s;
}

D4RValue::D4RValue(std::vector<dods_byte> &byte_args)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Byte b("");
	d_constant = build_constant_array(byte_args, b);
}

D4RValue::D4RValue(std::vector<dods_int8> &byte_int8)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Int8 b("");
	d_constant = build_constant_array(byte_int8, b);
}

D4RValue::D4RValue(std::vector<dods_uint16> &byte_uint16)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	UInt16 b("");
	d_constant = build_constant_array(byte_uint16, b);
}

D4RValue::D4RValue(std::vector<dods_int16> &byte_int16)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Int16 b("");
	d_constant = build_constant_array(byte_int16, b);
}

D4RValue::D4RValue(std::vector<dods_uint32> &byte_uint32)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	UInt32 b("");
	d_constant = build_constant_array(byte_uint32, b);
}

D4RValue::D4RValue(std::vector<dods_int32> &byte_int32)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Int32 b("");
	d_constant = build_constant_array(byte_int32, b);
}

D4RValue::D4RValue(std::vector<dods_uint64> &byte_uint64)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	UInt64 b("");
	d_constant = build_constant_array(byte_uint64, b);
}

D4RValue::D4RValue(std::vector<dods_int64> &byte_int64)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Int64 b("");
	d_constant = build_constant_array(byte_int64, b);
}

D4RValue::D4RValue(std::vector<dods_float32> &byte_float32)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Float32 b("");
	d_constant = build_constant_array(byte_float32, b);
}

D4RValue::D4RValue(std::vector<dods_float64> &byte_float64)
	: d_variable(0), d_func(0), d_args(0),  d_constant(0), d_value_kind(constant)
{
	Float64 b("");
	d_constant = build_constant_array(byte_float64, b);
}

D4RValue::~D4RValue() {
	// d_variable and d_func are weak pointers; don't delete.
	delete d_args;
	delete d_constant;
}

/** Return the BaseType * for a given RValue.
 *
 * @note A lingering issue with server functions is: Who or what is responsible
 * for deleting the BaseType* this method returns? Copying the BaseType wastes
 * memory but not copying it creates ambiguity since the BaseType* may point into
 * the DMR and thus should not be freed or it might be newly allocated storage
 * (in which case it should). For the function result, we have no way of knowing
 * how/if to dispose of the BaseType*. Sort this out ... (reference counting,
 * mark and sweep, ...). Maybe duplicate it before it contains data? Then it can be
 * deleted without affecting the DMR
 * jhrg 3/10/14
 *
 * @param dmr The DMR to pass to a function.
 * @return A BaseType* that holds the value.
 */
BaseType *
D4RValue::value(DMR &dmr)
{
	switch (d_value_kind) {
	case basetype:
		d_variable->read();
		d_variable->set_read_p(true);
		return d_variable;

	case function: {
		return (*d_func)(d_args, dmr);
	}

	case constant:
		return d_constant;

	default:
		throw InternalErr(__FILE__, __LINE__, "Unknown rvalue type.");
	};
}

} // namespace libdap

<|endoftext|>