<commit_before>#include "apfMPAS.h"
#include <apfMesh2.h>
#include <apfNumbering.h>
#include <diffMC/src/parma_ghostOwner.h>
#include <netcdf>

namespace apf {

using namespace netCDF;

struct MpasFile
{
  ~MpasFile()
  {
    delete [] x;
    delete [] y;
    delete [] z;
    delete [] conn;
  }
  int elements;
  int nodes;
  int nodesPerElement;
  double* x;
  double* y;
  double* z;
/* conn[i * vertexDegree + j] - 1
   is the index of the j'th node
   of element i */
  int* conn;
};

static int readDim(NcFile& f, const char* name)
{
  return f.getDim(name).getSize();
}

static double* readDoubles(NcFile& f, const char* name, int n)
{
  double* a = new double[n];
  NcVar v = f.getVar(name);
  v.getVar(a);
  return a;
}

static int* readInts(NcFile& f, const char* name, int n)
{
  int* a = new int[n];
  NcVar v = f.getVar(name);
  v.getVar(a);
  return a;
}

void readMpasFile(MpasFile& out, const char* filename)
{
  NcFile in(filename, NcFile::read);
  /* this is the dual of a hexagonal mesh,
     hence the reversing of terms */
  out.nodes = readDim(in, "nCells");
  printf("%d nodes\n", out.nodes);
  out.elements = readDim(in, "nVertices");
  printf("%d elements\n", out.elements);
  out.nodesPerElement = readDim(in, "vertexDegree");
  out.x = readDoubles(in, "xCell", out.nodes);
  out.y = readDoubles(in, "yCell", out.nodes);
  out.z = readDoubles(in, "zCell", out.nodes);
  out.conn = readInts(in, "cellsOnVertex", out.elements * out.nodesPerElement);
}

static int getType(int nodesPerElement)
{
  if (nodesPerElement == 3)
    return apf::Mesh::TRIANGLE;
  if (nodesPerElement == 4)
    return apf::Mesh::QUAD;
  abort();
  return 0;
}

void numberInitialNodes(MpasFile& in, apf::Mesh2* out,
    apf::MeshEntity** v)
{
  apf::Numbering* n = apf::createNumbering(out, "mpas_id", out->getShape(), 1);
  for (int i = 0; i < in.nodes; ++i)
    apf::number(n, v[i], 0, 0, i);
}

void buildInitialMesh(MpasFile& in, apf::Mesh2* out)
{
  apf::MeshEntity** v = new apf::MeshEntity* [in.nodes];
/* fake classification for now, deriveMdsModel will fix this up */
  apf::ModelEntity* c = out->findModelEntity(2, 0);
  int t = getType(in.nodesPerElement);
  for (int i = 0; i < in.nodes; ++i)
    v[i] = out->createVert(c);
  for (int i = 0; i < in.nodes; ++i) {
    apf::Vector3 x(in.x[i], in.y[i], in.z[i]);
    out->setPoint(v[i], 0, x);
  }
  for (int i = 0; i < in.elements; ++i) {
    apf::Downward ev;
    for (int j = 0; j < in.nodesPerElement; ++j) {
      int vi = in.conn[i * in.nodesPerElement + j] - 1;
/* zero indices (-1 after conversion) indicate that an MPAS
   vertex does not have an adjacent cell in that direction
   (it is a boundary vertex). In our dual mesh, we simply
   omit that dual element. This is correct and should not
   cause problems. */
      if (vi < 0)
        goto bad_vi;
      assert(vi < in.nodes);
      ev[j] = v[vi];
    }
    apf::buildElement(out, c, t, ev);
bad_vi:
    continue;
  }
  numberInitialNodes(in, out, v);
  delete [] v;
}

void removeIsolatedNodes(apf::Mesh2* m)
{
/* another problem with the dual: MPAS cells without adjacent
   cells become vertices with no adjacent elements in the
   dual mesh, which our codes don't handle.
   We have to give up on these cells, but tell the user about it.
   We also need to be aware of these omitted cells going forward */
  //apf::Numbering* nums = apf::createNumbering(m, "mpas_id", m->getShape(), 1);
  apf::MeshIterator* it = m->begin(0);
  int n = 0;
  apf::MeshEntity* e;
  while ((e = m->iterate(it)))
    if ( ! m->countUpward(e)) {
      /*int num =getNumber(nums, e, 0, 0);
        fprintf(stdout, "Missing vertex with number %d\n",num);
      */
      m->destroy(e);
      ++n;
    }
  m->end(it);
  if (n)
    fprintf(stderr,
        "warning: removed %d isolated nodes from MPAS dual mesh\n",
        n);
}

void loadMpasMesh(apf::Mesh2* m, const char* filename)
{
  assert(PCU_Comm_Peers() == 1);
  MpasFile f;
  readMpasFile(f, filename);
  buildInitialMesh(f, m);
  removeIsolatedNodes(m);
}

void writeMpasAssignments(apf::Mesh2* m, const char* filename) {
  NcFile in(filename, NcFile::read);
  /* this is the dual of a hexagonal mesh,
     hence the reversing of terms */
  int numMpasVtx = readDim(in, "nCells");

  apf::Numbering* n = apf::createNumbering(m, "mpas_id", m->getShape(), 1);

  /* collect N/#parts contiguous vertex assignments on each process
     (and deal with any remainders) */
  int numPerPart = numMpasVtx / PCU_Comm_Peers();
  apf::MeshIterator* itr = m->begin(0);
  apf::MeshEntity* e;
  int size;
  if (PCU_Comm_Self()==PCU_Comm_Peers()-1)
    size=numMpasVtx%numPerPart+numPerPart;
  else
    size=numPerPart;
  std::vector<int> vtxs(size,-1);
  PCU_Comm_Begin();
  while ((e = m->iterate(itr))) {
    if (!parma::isOwned(m, e))
      continue;
    int num = getNumber(n, e, 0, 0);
    int target = num / numPerPart;
    if (target>=PCU_Comm_Peers())
      target = PCU_Comm_Peers()-1;
    if (target == PCU_Comm_Self())
      vtxs[num%size] = PCU_Comm_Self();
    else
      PCU_COMM_PACK(target,num);
  }
  m->end(itr);

  PCU_Comm_Send();
  while (PCU_Comm_Receive()) {
    int owner =PCU_Comm_Sender();
    int num;
    PCU_COMM_UNPACK(num);
    vtxs[num%size]=owner;
  }

  // assign missing vertices to a random part id
  int count = 0;
  for (int i = 0;
       (i < size);
       i++)
    if (vtxs[i]==-1) {
      vtxs[i] = 0; //to be random
      //fprintf(stdout,"missing vertex %d\n",i+numPerPart*PCU_Comm_Self());
      count++;
    }
  fprintf(stdout,"missing vertices found %d\n",count);

  // use MPI IO to write the contiguous blocks to a single graph.info.part.<#parts> file
  // see https://gist.github.com/cwsmith/166d5beb400f3a8136f7 and the comments
  double startTime=MPI_Wtime();
  FILE* file;
  char name[32];

  sprintf(name,"graph.info.part.%d",PCU_Comm_Peers());
  file = fopen(name, "w");
  fseek(file,numPerPart*PCU_Comm_Self()*16,SEEK_SET);
  for (int i=0;i<size;i++)
    fprintf(file,"%-15d\n",vtxs[i]);

  fclose(file);
  double totalTime= MPI_Wtime()-startTime;
  PCU_Max_Doubles(&totalTime,1);
  if (!PCU_Comm_Self())
    fprintf(stdout,"File writing time: %f seconds\n", totalTime);
}

}
<commit_msg>almost fixed, prints lines correctly and adds extra lines<commit_after>#include "apfMPAS.h"
#include <apfMesh2.h>
#include <apfNumbering.h>
#include <diffMC/src/parma_ghostOwner.h>
#include <netcdf>

namespace apf {

using namespace netCDF;

struct MpasFile
{
  ~MpasFile()
  {
    delete [] x;
    delete [] y;
    delete [] z;
    delete [] conn;
  }
  int elements;
  int nodes;
  int nodesPerElement;
  double* x;
  double* y;
  double* z;
/* conn[i * vertexDegree + j] - 1
   is the index of the j'th node
   of element i */
  int* conn;
};

static int readDim(NcFile& f, const char* name)
{
  return f.getDim(name).getSize();
}

static double* readDoubles(NcFile& f, const char* name, int n)
{
  double* a = new double[n];
  NcVar v = f.getVar(name);
  v.getVar(a);
  return a;
}

static int* readInts(NcFile& f, const char* name, int n)
{
  int* a = new int[n];
  NcVar v = f.getVar(name);
  v.getVar(a);
  return a;
}

void readMpasFile(MpasFile& out, const char* filename)
{
  NcFile in(filename, NcFile::read);
  /* this is the dual of a hexagonal mesh,
     hence the reversing of terms */
  out.nodes = readDim(in, "nCells");
  printf("%d nodes\n", out.nodes);
  out.elements = readDim(in, "nVertices");
  printf("%d elements\n", out.elements);
  out.nodesPerElement = readDim(in, "vertexDegree");
  out.x = readDoubles(in, "xCell", out.nodes);
  out.y = readDoubles(in, "yCell", out.nodes);
  out.z = readDoubles(in, "zCell", out.nodes);
  out.conn = readInts(in, "cellsOnVertex", out.elements * out.nodesPerElement);
}

static int getType(int nodesPerElement)
{
  if (nodesPerElement == 3)
    return apf::Mesh::TRIANGLE;
  if (nodesPerElement == 4)
    return apf::Mesh::QUAD;
  abort();
  return 0;
}

void numberInitialNodes(MpasFile& in, apf::Mesh2* out,
    apf::MeshEntity** v)
{
  apf::Numbering* n = apf::createNumbering(out, "mpas_id", out->getShape(), 1);
  for (int i = 0; i < in.nodes; ++i)
    apf::number(n, v[i], 0, 0, i);
}

void buildInitialMesh(MpasFile& in, apf::Mesh2* out)
{
  apf::MeshEntity** v = new apf::MeshEntity* [in.nodes];
/* fake classification for now, deriveMdsModel will fix this up */
  apf::ModelEntity* c = out->findModelEntity(2, 0);
  int t = getType(in.nodesPerElement);
  for (int i = 0; i < in.nodes; ++i)
    v[i] = out->createVert(c);
  for (int i = 0; i < in.nodes; ++i) {
    apf::Vector3 x(in.x[i], in.y[i], in.z[i]);
    out->setPoint(v[i], 0, x);
  }
  for (int i = 0; i < in.elements; ++i) {
    apf::Downward ev;
    for (int j = 0; j < in.nodesPerElement; ++j) {
      int vi = in.conn[i * in.nodesPerElement + j] - 1;
/* zero indices (-1 after conversion) indicate that an MPAS
   vertex does not have an adjacent cell in that direction
   (it is a boundary vertex). In our dual mesh, we simply
   omit that dual element. This is correct and should not
   cause problems. */
      if (vi < 0)
        goto bad_vi;
      assert(vi < in.nodes);
      ev[j] = v[vi];
    }
    apf::buildElement(out, c, t, ev);
bad_vi:
    continue;
  }
  numberInitialNodes(in, out, v);
  delete [] v;
}

void removeIsolatedNodes(apf::Mesh2* m)
{
/* another problem with the dual: MPAS cells without adjacent
   cells become vertices with no adjacent elements in the
   dual mesh, which our codes don't handle.
   We have to give up on these cells, but tell the user about it.
   We also need to be aware of these omitted cells going forward */
  //apf::Numbering* nums = apf::createNumbering(m, "mpas_id", m->getShape(), 1);
  apf::MeshIterator* it = m->begin(0);
  int n = 0;
  apf::MeshEntity* e;
  while ((e = m->iterate(it)))
    if ( ! m->countUpward(e)) {
      /*int num =getNumber(nums, e, 0, 0);
        fprintf(stdout, "Missing vertex with number %d\n",num);
      */
      m->destroy(e);
      ++n;
    }
  m->end(it);
  if (n)
    fprintf(stderr,
        "warning: removed %d isolated nodes from MPAS dual mesh\n",
        n);
}

void loadMpasMesh(apf::Mesh2* m, const char* filename)
{
  assert(PCU_Comm_Peers() == 1);
  MpasFile f;
  readMpasFile(f, filename);
  buildInitialMesh(f, m);
  removeIsolatedNodes(m);
}

void writeMpasAssignments(apf::Mesh2* m, const char* filename) {
  NcFile in(filename, NcFile::read);
  /* this is the dual of a hexagonal mesh,
     hence the reversing of terms */
  int numMpasVtx = readDim(in, "nCells");

  apf::Numbering* n = apf::createNumbering(m, "mpas_id", m->getShape(), 1);

  /* collect N/#parts contiguous vertex assignments on each process
     (and deal with any remainders) */
  int numPerPart = numMpasVtx / PCU_Comm_Peers();
  apf::MeshIterator* itr = m->begin(0);
  apf::MeshEntity* e;
  int size;
  if (PCU_Comm_Self()==PCU_Comm_Peers()-1)
    size=numMpasVtx%numPerPart+numPerPart;
  else
    size=numPerPart;
  std::vector<int> vtxs(size,-1);
  PCU_Comm_Begin();
  while ((e = m->iterate(itr))) {
    if (!parma::isOwned(m, e))
      continue;
    int num = getNumber(n, e, 0, 0);
    int target = num / numPerPart;
    if (target>=PCU_Comm_Peers())
      target = PCU_Comm_Peers()-1;
    if (target == PCU_Comm_Self())
      vtxs[num%size] = PCU_Comm_Self();
    else
      PCU_COMM_PACK(target,num);
  }
  m->end(itr);

  PCU_Comm_Send();
  while (PCU_Comm_Receive()) {
    int owner =PCU_Comm_Sender();
    int num;
    PCU_COMM_UNPACK(num);
    vtxs[num%size]=owner;
  }

  // assign missing vertices to a random part id
  int count = 0;
  for (int i = 0;
       (i < size);
       i++)
    if (vtxs[i]==-1) {
      vtxs[i] = 0; //to be random
      //fprintf(stdout,"missing vertex %d\n",i+numPerPart*PCU_Comm_Self());
      count++;
    }
  if (count)
    fprintf(stdout,"missing vertices found %d on part %d\n",count,PCU_Comm_Self());

  // use MPI IO to write the contiguous blocks to a single graph.info.part.<#parts> file
  // see https://gist.github.com/cwsmith/166d5beb400f3a8136f7 and the comments
  double startTime=MPI_Wtime();
  MPI_File file;
  char name[32];

  sprintf(name,"graph.info.part.%d",PCU_Comm_Peers());
  MPI_File_open(MPI_COMM_WORLD, name, MPI_MODE_CREATE|MPI_MODE_WRONLY,
		MPI_INFO_NULL, &file);
  MPI_Offset offset = numPerPart*PCU_Comm_Self()*16;
  MPI_File_seek(file, offset, MPI_SEEK_SET);
  MPI_Datatype filetype;
  MPI_Type_contiguous(size,MPI_CHAR,&filetype);
  MPI_Type_commit(&filetype);
  MPI_File_set_view(file,offset,MPI_CHAR,MPI_CHAR,"internal",MPI_INFO_NULL);
  char* str = new char[16*size];
  for (int i=0;
       i<size;
       i++) {
    sprintf(str,"%s%-15d\n",str,vtxs[i]);
  }
  MPI_Status status;
  MPI_File_write(file,str,strlen(str),MPI_CHAR,&status);

  delete [] str;
  MPI_File_close(&file);
  double totalTime= MPI_Wtime()-startTime;
  PCU_Max_Doubles(&totalTime,1);
  if (!PCU_Comm_Self())
    fprintf(stdout,"File writing time: %f seconds\n", totalTime);
}

}
<|endoftext|>


<commit_before>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#include "bsecategories.hh"
#include "bsesource.hh"
#include "bseprocedure.hh"
#include "bsemain.hh"
#include "bsestandardsynths.hh"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

static gchar *indent_inc = NULL;
static guint spacing = 1;
static FILE *f_out = NULL;
static GType root = 0;
static gboolean recursion = TRUE;
static gboolean feature_blurb = FALSE;
static gboolean feature_channels = FALSE;

/*
  #define	O_SPACE	"\\as"
  #define	O_ESPACE " "
  #define	O_BRANCH "\\aE"
  #define	O_VLINE "\\al"
  #define	O_LLEAF	"\\aL"
  #define	O_KEY_FILL "_"
*/

#define	O_SPACE	" "
#define	O_ESPACE ""
#define	O_BRANCH "+"
#define	O_VLINE "|"
#define	O_LLEAF	"`"
#define	O_KEY_FILL "_"

static void
show_nodes (GType        type,
	    GType        sibling,
	    const gchar *indent)
{
  GType   *children;
  guint i;

  if (!type)
    return;

  children = g_type_children (type, NULL);

  if (type != root)
    for (i = 0; i < spacing; i++)
      fprintf (f_out, "%s%s\n", indent, O_VLINE);

  fprintf (f_out, "%s%s%s%s",
	   indent,
	   sibling ? O_BRANCH : (type != root ? O_LLEAF : O_SPACE),
	   O_ESPACE,
	   g_type_name (type));

  for (i = strlen (g_type_name (type)); i <= strlen (indent_inc); i++)
    fputs (O_KEY_FILL, f_out);

  if (feature_blurb && bse_type_get_blurb (type))
    {
      fputs ("\t[", f_out);
      fputs (bse_type_get_blurb (type), f_out);
      fputs ("]", f_out);
    }

  if (G_TYPE_IS_ABSTRACT (type))
    fputs ("\t(abstract)", f_out);

  if (feature_channels && g_type_is_a (type, BSE_TYPE_SOURCE))
    {
      BseSourceClass *klass = (BseSourceClass*) g_type_class_ref (type);
      gchar buffer[1024];

      sprintf (buffer,
	       "\t(ichannels %u) (ochannels %u)",
	       klass->channel_defs.n_ichannels,
	       klass->channel_defs.n_ochannels);
      fputs (buffer, f_out);
      g_type_class_unref (klass);
    }

  fputc ('\n', f_out);

  if (children && recursion)
    {
      gchar *new_indent;
      GType   *child;

      if (sibling)
	new_indent = g_strconcat (indent, O_VLINE, indent_inc, NULL);
      else
	new_indent = g_strconcat (indent, O_SPACE, indent_inc, NULL);

      for (child = children; *child; child++)
	show_nodes (child[0], child[1], new_indent);

      g_free (new_indent);
    }

  g_free (children);
}

static void
show_cats (void)
{
  BseCategorySeq *cseq;
  guint i;

  cseq = bse_categories_match_typed ("*", 0);
  for (i = 0; i < cseq->n_cats; i++)
    fprintf (f_out, "%s\t(%s)\n",
	     cseq->cats[i]->category,
	     cseq->cats[i]->type);
  bse_category_seq_free (cseq);
}

static void
show_procdoc (void)
{
  BseCategorySeq *cseq;
  guint i;
  const gchar *nullstr = ""; // "???";

  cseq = bse_categories_match_typed ("*", BSE_TYPE_PROCEDURE);
  for (i = 0; i < cseq->n_cats; i++)
    {
      GType type = g_type_from_name (cseq->cats[i]->type);
      BseProcedureClass *klass = (BseProcedureClass*) g_type_class_ref (type);
      gchar *pname = g_type_name_to_sname (cseq->cats[i]->type);
      const gchar *blurb = bse_type_get_blurb (type);
      guint j;

      fprintf (f_out, "/**\n * %s\n", pname);
      for (j = 0; j < klass->n_in_pspecs; j++)
	{
	  GParamSpec *pspec = G_PARAM_SPEC (klass->in_pspecs[j]);

	  fprintf (f_out, " * @%s: %s\n",
		   pspec->name,
		   g_param_spec_get_blurb (pspec) ? g_param_spec_get_blurb (pspec) : nullstr);
	}
      for (j = 0; j < klass->n_out_pspecs; j++)
	{
	  GParamSpec *pspec = G_PARAM_SPEC (klass->out_pspecs[j]);

	  fprintf (f_out, " * @Returns: %s: %s\n",
		   pspec->name,
		   g_param_spec_get_blurb (pspec) ? g_param_spec_get_blurb (pspec) : nullstr);
	}
      if (blurb)
	fprintf (f_out, " * %s\n", blurb);
      fprintf (f_out, " **/\n");
      g_type_class_unref (klass);
      g_free (pname);
    }
  bse_category_seq_free (cseq);
}

static gint
help (gchar *arg)
{
  fprintf (stderr, "usage: query <qualifier> [-r <type>] [-{i|b} \"\"] [-s #] [-{h|x|y}]\n");
  fprintf (stderr, "       -r       specifiy root type\n");
  fprintf (stderr, "       -n       don't descend type tree\n");
  fprintf (stderr, "       -p       include plugins\n");
  fprintf (stderr, "       -x       show type blurbs\n");
  fprintf (stderr, "       -y       show source channels\n");
  fprintf (stderr, "       -h       guess what ;)\n");
  fprintf (stderr, "       -b       specifiy indent string\n");
  fprintf (stderr, "       -i       specifiy incremental indent string\n");
  fprintf (stderr, "       -s       specifiy line spacing\n");
  fprintf (stderr, "       -:f      make all warnings fatal\n");
  fprintf (stderr, "qualifiers:\n");
  fprintf (stderr, "       froots     iterate over fundamental roots\n");
  fprintf (stderr, "       tree       print BSE type tree\n");
  fprintf (stderr, "       cats       print categories\n");
  fprintf (stderr, "       procdoc    print procedure documentation\n");
  fprintf (stderr, "       synth <x>  dump standard synth <x> definition\n");

  return arg != NULL;
}

int
main (gint   argc,
      gchar *argv[])
{
  gboolean gen_froots = 0;
  gboolean gen_tree = 0;
  gboolean gen_cats = 0;
  gboolean gen_procdoc = 0;
  gchar *show_synth = NULL;
  gchar *root_name = NULL;
  const char *iindent = "";
  const char *pluginbool = "load-core-plugins=0";
  const char *scriptbool = "load-core-scripts=0";
  f_out = stdout;

  bse_init_test (&argc, argv);
  int i;
  for (i = 1; i < argc; i++)
    {
      if (strcmp ("-s", argv[i]) == 0)
	{
	  i++;
	  if (i < argc)
	    spacing = atoi (argv[i]);
	}
      else if (strcmp ("-i", argv[i]) == 0)
	{
	  i++;
	  if (i < argc)
	    {
	      char *p;
	      guint n;

	      p = argv[i];
	      while (*p)
		p++;
	      n = p - argv[i];
	      indent_inc = g_new (gchar, n * strlen (O_SPACE) + 1);
	      *indent_inc = 0;
	      while (n)
		{
		  n--;
		  strcpy (indent_inc, O_SPACE);
		}
	    }
	}
      else if (strcmp ("-b", argv[i]) == 0)
	{
	  i++;
	  if (i < argc)
	    iindent = argv[i];
	}
      else if (strcmp ("-r", argv[i]) == 0)
	{
	  i++;
	  if (i < argc)
	    root_name = argv[i];
	}
      else if (strcmp ("-n", argv[i]) == 0)
	{
	  recursion = FALSE;
	}
      else if (strcmp ("-x", argv[i]) == 0)
	{
	  feature_blurb = TRUE;
	}
      else if (strcmp ("-y", argv[i]) == 0)
	{
	  feature_channels = TRUE;
	}
      else if (strcmp ("froots", argv[i]) == 0)
	{
	  gen_froots = 1;
	}
      else if (strcmp ("synth", argv[i]) == 0 && i + 1 < argc)
	{
	  show_synth = argv[++i];
	}
      else if (strcmp ("tree", argv[i]) == 0)
	{
	  gen_tree = 1;
	}
      else if (strcmp ("cats", argv[i]) == 0)
	{
	  gen_cats = 1;
	}
      else if (strcmp ("procdoc", argv[i]) == 0)
	{
	  gen_procdoc = 1;
	}
      else if (strcmp ("-p", argv[i]) == 0)
        pluginbool = "load-core-plugins=1";
      else if (strcmp ("-:f", argv[i]) == 0)
	{
	  g_log_set_always_fatal (GLogLevelFlags (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL |
                                                  g_log_set_always_fatal (GLogLevelFlags (G_LOG_FATAL_MASK))));
	}
      else if (strcmp ("-h", argv[i]) == 0)
	{
	  return help (NULL);
	}
      else if (strcmp ("--help", argv[i]) == 0)
	{
	  return help (NULL);
	}
      else
	return help (argv[i]);
    }
  bse_init_inprocess (&argc, argv, "BseQuery", Bse::cstrings_to_vector (pluginbool, scriptbool, NULL));
  if (root_name)
    root = g_type_from_name (root_name);
  else
    root = BSE_TYPE_OBJECT;
  if (!gen_froots && !gen_tree && !gen_cats && !gen_procdoc && !show_synth)
    return help (argv[i-1]);
  if (!indent_inc)
    {
      indent_inc = g_new (gchar, strlen (O_SPACE) + 1);
      *indent_inc = 0;
      strcpy (indent_inc, O_SPACE);
      strcpy (indent_inc, O_SPACE);
      strcpy (indent_inc, O_SPACE);
    }

  if (gen_tree)
    show_nodes (root, 0, iindent);
  if (gen_froots)
    {
      root = ~0;
      for (i = 0; i <= G_TYPE_FUNDAMENTAL_MAX; i += G_TYPE_MAKE_FUNDAMENTAL (1))
	{
	  const char *name = g_type_name (i);
	  if (name)
	    show_nodes (i, 0, iindent);
	}
    }
  if (gen_cats)
    show_cats ();
  if (gen_procdoc)
    show_procdoc ();
  if (show_synth)
    {
      gchar *text = bse_standard_synth_inflate (show_synth, NULL);
      g_print ("%s", text);
      g_free (text);
    }

  return 0;
}
<commit_msg>BSE: fix bsequery initialization to avoid crashing<commit_after>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#include "bsecategories.hh"
#include "bsesource.hh"
#include "bseprocedure.hh"
#include "bsemain.hh"
#include "bsestandardsynths.hh"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

static gchar *indent_inc = NULL;
static guint spacing = 1;
static FILE *f_out = NULL;
static GType root = 0;
static gboolean recursion = TRUE;
static gboolean feature_blurb = FALSE;
static gboolean feature_channels = FALSE;

/*
  #define	O_SPACE	"\\as"
  #define	O_ESPACE " "
  #define	O_BRANCH "\\aE"
  #define	O_VLINE "\\al"
  #define	O_LLEAF	"\\aL"
  #define	O_KEY_FILL "_"
*/

#define	O_SPACE	" "
#define	O_ESPACE ""
#define	O_BRANCH "+"
#define	O_VLINE "|"
#define	O_LLEAF	"`"
#define	O_KEY_FILL "_"

static void
show_nodes (GType        type,
	    GType        sibling,
	    const gchar *indent)
{
  GType   *children;
  guint i;

  if (!type)
    return;

  children = g_type_children (type, NULL);

  if (type != root)
    for (i = 0; i < spacing; i++)
      fprintf (f_out, "%s%s\n", indent, O_VLINE);

  fprintf (f_out, "%s%s%s%s",
	   indent,
	   sibling ? O_BRANCH : (type != root ? O_LLEAF : O_SPACE),
	   O_ESPACE,
	   g_type_name (type));

  for (i = strlen (g_type_name (type)); i <= strlen (indent_inc); i++)
    fputs (O_KEY_FILL, f_out);

  if (feature_blurb && bse_type_get_blurb (type))
    {
      fputs ("\t[", f_out);
      fputs (bse_type_get_blurb (type), f_out);
      fputs ("]", f_out);
    }

  if (G_TYPE_IS_ABSTRACT (type))
    fputs ("\t(abstract)", f_out);

  if (feature_channels && g_type_is_a (type, BSE_TYPE_SOURCE))
    {
      BseSourceClass *klass = (BseSourceClass*) g_type_class_ref (type);
      gchar buffer[1024];

      sprintf (buffer,
	       "\t(ichannels %u) (ochannels %u)",
	       klass->channel_defs.n_ichannels,
	       klass->channel_defs.n_ochannels);
      fputs (buffer, f_out);
      g_type_class_unref (klass);
    }

  fputc ('\n', f_out);

  if (children && recursion)
    {
      gchar *new_indent;
      GType   *child;

      if (sibling)
	new_indent = g_strconcat (indent, O_VLINE, indent_inc, NULL);
      else
	new_indent = g_strconcat (indent, O_SPACE, indent_inc, NULL);

      for (child = children; *child; child++)
	show_nodes (child[0], child[1], new_indent);

      g_free (new_indent);
    }

  g_free (children);
}

static void
show_cats (void)
{
  BseCategorySeq *cseq;
  guint i;

  cseq = bse_categories_match_typed ("*", 0);
  for (i = 0; i < cseq->n_cats; i++)
    fprintf (f_out, "%s\t(%s)\n",
	     cseq->cats[i]->category,
	     cseq->cats[i]->type);
  bse_category_seq_free (cseq);
}

static void
show_procdoc (void)
{
  BseCategorySeq *cseq;
  guint i;
  const gchar *nullstr = ""; // "???";

  cseq = bse_categories_match_typed ("*", BSE_TYPE_PROCEDURE);
  for (i = 0; i < cseq->n_cats; i++)
    {
      GType type = g_type_from_name (cseq->cats[i]->type);
      BseProcedureClass *klass = (BseProcedureClass*) g_type_class_ref (type);
      gchar *pname = g_type_name_to_sname (cseq->cats[i]->type);
      const gchar *blurb = bse_type_get_blurb (type);
      guint j;

      fprintf (f_out, "/**\n * %s\n", pname);
      for (j = 0; j < klass->n_in_pspecs; j++)
	{
	  GParamSpec *pspec = G_PARAM_SPEC (klass->in_pspecs[j]);

	  fprintf (f_out, " * @%s: %s\n",
		   pspec->name,
		   g_param_spec_get_blurb (pspec) ? g_param_spec_get_blurb (pspec) : nullstr);
	}
      for (j = 0; j < klass->n_out_pspecs; j++)
	{
	  GParamSpec *pspec = G_PARAM_SPEC (klass->out_pspecs[j]);

	  fprintf (f_out, " * @Returns: %s: %s\n",
		   pspec->name,
		   g_param_spec_get_blurb (pspec) ? g_param_spec_get_blurb (pspec) : nullstr);
	}
      if (blurb)
	fprintf (f_out, " * %s\n", blurb);
      fprintf (f_out, " **/\n");
      g_type_class_unref (klass);
      g_free (pname);
    }
  bse_category_seq_free (cseq);
}

static gint
help (gchar *arg)
{
  fprintf (stderr, "usage: query <qualifier> [-r <type>] [-{i|b} \"\"] [-s #] [-{h|x|y}]\n");
  fprintf (stderr, "       -r       specifiy root type\n");
  fprintf (stderr, "       -n       don't descend type tree\n");
  fprintf (stderr, "       -p       include plugins\n");
  fprintf (stderr, "       -x       show type blurbs\n");
  fprintf (stderr, "       -y       show source channels\n");
  fprintf (stderr, "       -h       guess what ;)\n");
  fprintf (stderr, "       -b       specifiy indent string\n");
  fprintf (stderr, "       -i       specifiy incremental indent string\n");
  fprintf (stderr, "       -s       specifiy line spacing\n");
  fprintf (stderr, "       -:f      make all warnings fatal\n");
  fprintf (stderr, "qualifiers:\n");
  fprintf (stderr, "       froots     iterate over fundamental roots\n");
  fprintf (stderr, "       tree       print BSE type tree\n");
  fprintf (stderr, "       cats       print categories\n");
  fprintf (stderr, "       procdoc    print procedure documentation\n");
  fprintf (stderr, "       synth <x>  dump standard synth <x> definition\n");

  return arg != NULL;
}

int
main (gint   argc,
      gchar *argv[])
{
  gboolean gen_froots = 0;
  gboolean gen_tree = 0;
  gboolean gen_cats = 0;
  gboolean gen_procdoc = 0;
  gchar *show_synth = NULL;
  gchar *root_name = NULL;
  const char *iindent = "";
  const char *pluginbool = "load-core-plugins=0";
  const char *scriptbool = "load-core-scripts=0";
  f_out = stdout;

  bse_init_inprocess (&argc, argv, "BseQuery", Bse::cstrings_to_vector (pluginbool, scriptbool, NULL));
  // bse_init_test (&argc, argv);
  int i;
  for (i = 1; i < argc; i++)
    {
      if (strcmp ("-s", argv[i]) == 0)
	{
	  i++;
	  if (i < argc)
	    spacing = atoi (argv[i]);
	}
      else if (strcmp ("-i", argv[i]) == 0)
	{
	  i++;
	  if (i < argc)
	    {
	      char *p;
	      guint n;

	      p = argv[i];
	      while (*p)
		p++;
	      n = p - argv[i];
	      indent_inc = g_new (gchar, n * strlen (O_SPACE) + 1);
	      *indent_inc = 0;
	      while (n)
		{
		  n--;
		  strcpy (indent_inc, O_SPACE);
		}
	    }
	}
      else if (strcmp ("-b", argv[i]) == 0)
	{
	  i++;
	  if (i < argc)
	    iindent = argv[i];
	}
      else if (strcmp ("-r", argv[i]) == 0)
	{
	  i++;
	  if (i < argc)
	    root_name = argv[i];
	}
      else if (strcmp ("-n", argv[i]) == 0)
	{
	  recursion = FALSE;
	}
      else if (strcmp ("-x", argv[i]) == 0)
	{
	  feature_blurb = TRUE;
	}
      else if (strcmp ("-y", argv[i]) == 0)
	{
	  feature_channels = TRUE;
	}
      else if (strcmp ("froots", argv[i]) == 0)
	{
	  gen_froots = 1;
	}
      else if (strcmp ("synth", argv[i]) == 0 && i + 1 < argc)
	{
	  show_synth = argv[++i];
	}
      else if (strcmp ("tree", argv[i]) == 0)
	{
	  gen_tree = 1;
	}
      else if (strcmp ("cats", argv[i]) == 0)
	{
	  gen_cats = 1;
	}
      else if (strcmp ("procdoc", argv[i]) == 0)
	{
	  gen_procdoc = 1;
	}
      else if (strcmp ("-p", argv[i]) == 0)
        pluginbool = "load-core-plugins=1";
      else if (strcmp ("-:f", argv[i]) == 0)
	{
	  g_log_set_always_fatal (GLogLevelFlags (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL |
                                                  g_log_set_always_fatal (GLogLevelFlags (G_LOG_FATAL_MASK))));
	}
      else if (strcmp ("-h", argv[i]) == 0)
	{
	  return help (NULL);
	}
      else if (strcmp ("--help", argv[i]) == 0)
	{
	  return help (NULL);
	}
      else
	return help (argv[i]);
    }
  // bse_init_inprocess (&argc, argv, "BseQuery", Bse::cstrings_to_vector (pluginbool, scriptbool, NULL));
  if (root_name)
    root = g_type_from_name (root_name);
  else
    root = BSE_TYPE_OBJECT;
  if (!gen_froots && !gen_tree && !gen_cats && !gen_procdoc && !show_synth)
    return help (argv[i-1]);
  if (!indent_inc)
    {
      indent_inc = g_new (gchar, strlen (O_SPACE) + 1);
      *indent_inc = 0;
      strcpy (indent_inc, O_SPACE);
      strcpy (indent_inc, O_SPACE);
      strcpy (indent_inc, O_SPACE);
    }

  if (gen_tree)
    show_nodes (root, 0, iindent);
  if (gen_froots)
    {
      root = ~0;
      for (i = 0; i <= G_TYPE_FUNDAMENTAL_MAX; i += G_TYPE_MAKE_FUNDAMENTAL (1))
	{
	  const char *name = g_type_name (i);
	  if (name)
	    show_nodes (i, 0, iindent);
	}
    }
  if (gen_cats)
    show_cats ();
  if (gen_procdoc)
    show_procdoc ();
  if (show_synth)
    {
      gchar *text = bse_standard_synth_inflate (show_synth, NULL);
      g_print ("%s", text);
      g_free (text);
    }

  return 0;
}
<|endoftext|>


<commit_before><commit_msg>Cast Buffers to Char * for Winsock<commit_after><|endoftext|>


<commit_before>#include <cassert>
#include <climits>
#include <cmath>

#include "rational.hh"
#include "zs_error.hh"
#include "zs_memory.hh"

static_assert(sizeof(int) < sizeof(long long),
              "integer overflow cannot be treated properly");

using namespace std;

// TODO: make this as constructor.
Rational& Rational::normalized_reset(long long n, long long d){
  if(d == 0)
    throw_zs_error({}, "Rational::denominator is 0");

  auto gcd_val = gcd(n, d);
  n /= gcd_val;
  d /= gcd_val;

  if(d < 0){
    n = -n;
    d = -d;
  }

  if(n < INT_MIN || n > INT_MAX
     || d < INT_MIN || d > INT_MAX){
    overflow_ = true;
    float_ = (double)n / (double)d;
  }else{
    ratio_.n_ = static_cast<int>(n);
    ratio_.d_ = static_cast<int>(d);
  }

  return *this;
}

Rational::operator double() const{
  assert(is_convertible<double>());
  if(overflow_){
    return float_;
  }else{
    return static_cast<double>(numerator()) / static_cast<double>(denominator());
  }
}

Rational& Rational::expt(const Rational& other){
  if(other.denominator() != 1){
    overflow_ = true;
    float_ = std::pow(static_cast<double>(*this),
                      static_cast<double>(other));
    return *this;
  }

  const auto base_r = *this;
  normalized_reset(1, 1);

  auto ex = other.numerator();
  for(; ex > 0; --ex){
    operator*=(base_r);
    if(overflow_) break;
  }

  if(overflow_){
    auto base_d = static_cast<double>(base_r);
    for(; ex > 0; --ex) float_ *= base_d;
  }

  return *this;
}

Rational rationalize(double answer, double error){
  // from:
  // http://en.wikipedia.org/wiki/Continued_fraction#Infinite_continued_fractions
  double d = answer;

  int h_2 = 0, h_1 = 1;
  int k_2 = 1, k_1 = 0;
  long long h_0;
  long long k_0;

  while(1){
    auto int_p = (long long)floor(d);
    auto frac_p = d - floor(d);
    d = 1 / frac_p;

    h_0 = int_p * h_1 + h_2;
    k_0 = int_p * k_1 + k_2;

    if(h_0 < INT_MIN || h_0 > INT_MAX
       || k_0 < INT_MIN || k_0 > INT_MAX){
      // integer overflow
      break;
    }

    auto sub_ans = (double)h_0 / (double)k_0;

    if(abs(sub_ans - answer) <= error){
      break;
    }

    h_2 = h_1;
    h_1 = (int)h_0;
    k_2 = k_1;
    k_1 = (int)k_0;
  }

  return Rational{h_0 , k_0};
}

// utilities
template<>
int coerce(Lisp_ptr p){
  if(p.tag() == Ptr_tag::integer){
    return p.get<int>();
  }else{
    UNEXP_DEFAULT();
  }
}

template<>
Rational coerce(Lisp_ptr p){
  if(p.tag() == Ptr_tag::rational){
    return *p.get<Rational*>();
  }else{
    return Rational(coerce<int>(p), 1);
  }
}

template<>
double coerce(Lisp_ptr p){
  if(p.tag() == Ptr_tag::real){
    return *(p.get<double*>());
  }else{
    return static_cast<double>(coerce<Rational>(p));
  }
}

template<>
Complex coerce(Lisp_ptr p){
  if(p.tag() == Ptr_tag::complex){
    return *(p.get<Complex*>());
  }else{
    return Complex(coerce<double>(p), 0);
  }
}

bool is_numeric_type(Lisp_ptr p){
  switch(p.tag()){
  case Ptr_tag::integer:
  case Ptr_tag::rational:
  case Ptr_tag::real:
  case Ptr_tag::complex:
    return true;
  case Ptr_tag::undefined: case Ptr_tag::boolean:
  case Ptr_tag::character: case Ptr_tag::cons:
  case Ptr_tag::symbol:
  case Ptr_tag::i_procedure: case Ptr_tag::n_procedure:
  case Ptr_tag::continuation: case Ptr_tag::syntax_rules:
  case Ptr_tag::string:    case Ptr_tag::vector:
  case Ptr_tag::input_port: case Ptr_tag::output_port:
  case Ptr_tag::env:  case Ptr_tag::syntactic_closure:
  case Ptr_tag::vm_op: case Ptr_tag::vm_argcount:
  case Ptr_tag::notation:
  default:
    return false;
  }
}

bool is_numeric_convertible(Lisp_ptr p, Ptr_tag tag){
  switch(p.tag()){
  case Ptr_tag::integer:
    if(tag == Ptr_tag::integer) return true;
    // fall through
  case Ptr_tag::rational:
    if(tag == Ptr_tag::rational) return true;
    // fall through
  case Ptr_tag::real:
    if(tag == Ptr_tag::real) return true;
    // fall through
  case Ptr_tag::complex:
    return (tag == Ptr_tag::complex);
  case Ptr_tag::undefined: case Ptr_tag::boolean:
  case Ptr_tag::character: case Ptr_tag::cons:
  case Ptr_tag::symbol:
  case Ptr_tag::i_procedure: case Ptr_tag::n_procedure:
  case Ptr_tag::continuation: case Ptr_tag::syntax_rules:
  case Ptr_tag::string:    case Ptr_tag::vector:
  case Ptr_tag::input_port: case Ptr_tag::output_port:
  case Ptr_tag::env:  case Ptr_tag::syntactic_closure:
  case Ptr_tag::vm_op: case Ptr_tag::vm_argcount:
  case Ptr_tag::notation:
  default:
    return false;
  }
}

Lisp_ptr wrap_number(const Rational& q){
  if(q.is_convertible<int>()){
    return Lisp_ptr{static_cast<int>(q)};
  }else if(q.is_convertible<Rational>()){
    return {zs_new<Rational>(q)};
  }else{
    print_zs_warning("integer overflow occured. coerced into real.");
    return {zs_new<double>(static_cast<double>(q))};
  }
}

Lisp_ptr wrap_number(double d){
  return {zs_new<double>(d)};
}

Lisp_ptr wrap_number(const Complex& z){
  return {zs_new<Complex>(z)};
}

Lisp_ptr to_exact(Lisp_ptr p){
  switch(p.tag()){
  case Ptr_tag::integer:
  case Ptr_tag::rational:
    return p;
  case Ptr_tag::real:
    return wrap_number(static_cast<int>(*p.get<double*>()));
  case Ptr_tag::complex:
    throw_zs_error(p, "number error: conversion from complex to exact number is not supprted.\n");
  case Ptr_tag::undefined:
  case Ptr_tag::boolean:
  case Ptr_tag::character:
  case Ptr_tag::cons:
  case Ptr_tag::symbol:
  case Ptr_tag::i_procedure:
  case Ptr_tag::n_procedure:
  case Ptr_tag::continuation:
  case Ptr_tag::string:
  case Ptr_tag::vector:
  case Ptr_tag::input_port:
  case Ptr_tag::output_port:
  case Ptr_tag::env:
  case Ptr_tag::syntactic_closure:
  case Ptr_tag::syntax_rules:
  case Ptr_tag::vm_op:
  case Ptr_tag::vm_argcount:
  case Ptr_tag::notation:
  default:
    UNEXP_DEFAULT();
  }
}

Lisp_ptr to_inexact(Lisp_ptr p){
  switch(p.tag()){
  case Ptr_tag::integer:
  case Ptr_tag::rational:
    return wrap_number(coerce<double>(p));
  case Ptr_tag::real:
  case Ptr_tag::complex:
    return p;
  case Ptr_tag::undefined:
  case Ptr_tag::boolean:
  case Ptr_tag::character:
  case Ptr_tag::cons:
  case Ptr_tag::symbol:
  case Ptr_tag::i_procedure:
  case Ptr_tag::n_procedure:
  case Ptr_tag::continuation:
  case Ptr_tag::string:
  case Ptr_tag::vector:
  case Ptr_tag::input_port:
  case Ptr_tag::output_port:
  case Ptr_tag::env:
  case Ptr_tag::syntactic_closure:
  case Ptr_tag::syntax_rules:
  case Ptr_tag::vm_op:
  case Ptr_tag::vm_argcount:
  case Ptr_tag::notation:
  default:
    UNEXP_DEFAULT();
  }
}
<commit_msg>trivial cleanup<commit_after>#include <cassert>
#include <climits>
#include <cmath>

#include "rational.hh"
#include "zs_error.hh"
#include "zs_memory.hh"

static_assert(sizeof(int) < sizeof(long long),
              "integer overflow cannot be treated properly");

using namespace std;

// TODO: make this as constructor.
Rational& Rational::normalized_reset(long long n, long long d){
  if(d == 0)
    throw_zs_error({}, "Rational::denominator is 0");

  auto gcd_val = gcd(n, d);
  n /= gcd_val;
  d /= gcd_val;

  if(d < 0){
    n = -n;
    d = -d;
  }

  if(n < INT_MIN || n > INT_MAX
     || d < INT_MIN || d > INT_MAX){
    overflow_ = true;
    float_ = (double)n / (double)d;
  }else{
    ratio_.n_ = static_cast<int>(n);
    ratio_.d_ = static_cast<int>(d);
  }

  return *this;
}

Rational::operator double() const{
  assert(is_convertible<double>());
  if(overflow_){
    return float_;
  }else{
    return static_cast<double>(numerator()) / static_cast<double>(denominator());
  }
}

Rational& Rational::expt(const Rational& other){
  if(other.denominator() != 1){
    overflow_ = true;
    float_ = std::pow(static_cast<double>(*this),
                      static_cast<double>(other));
    return *this;
  }

  const auto base_r = *this;
  normalized_reset(1, 1);

  auto ex = other.numerator();
  for(; ex > 0; --ex){
    operator*=(base_r);
    if(overflow_) break;
  }

  if(overflow_){
    auto base_d = static_cast<double>(base_r);
    for(; ex > 0; --ex) float_ *= base_d;
  }

  return *this;
}

Rational rationalize(double answer, double error){
  // from:
  // http://en.wikipedia.org/wiki/Continued_fraction#Infinite_continued_fractions
  double d = answer;

  int h_2 = 0, h_1 = 1;
  int k_2 = 1, k_1 = 0;
  long long h_0;
  long long k_0;

  while(1){
    auto int_p = (long long)floor(d);
    auto frac_p = d - floor(d);
    d = 1 / frac_p;

    h_0 = int_p * h_1 + h_2;
    k_0 = int_p * k_1 + k_2;

    if(h_0 < INT_MIN || h_0 > INT_MAX
       || k_0 < INT_MIN || k_0 > INT_MAX){
      // integer overflow
      break;
    }

    auto sub_ans = (double)h_0 / (double)k_0;

    if(abs(sub_ans - answer) <= error){
      break;
    }

    h_2 = h_1;
    h_1 = (int)h_0;
    k_2 = k_1;
    k_1 = (int)k_0;
  }

  return Rational{h_0 , k_0};
}

// utilities
template<>
int coerce(Lisp_ptr p){
  if(p.tag() == Ptr_tag::integer){
    return p.get<int>();
  }else{
    UNEXP_DEFAULT();
  }
}

template<>
Rational coerce(Lisp_ptr p){
  if(p.tag() == Ptr_tag::rational){
    return *p.get<Rational*>();
  }else{
    return Rational(coerce<int>(p));
  }
}

template<>
double coerce(Lisp_ptr p){
  if(p.tag() == Ptr_tag::real){
    return *(p.get<double*>());
  }else{
    return static_cast<double>(coerce<Rational>(p));
  }
}

template<>
Complex coerce(Lisp_ptr p){
  if(p.tag() == Ptr_tag::complex){
    return *(p.get<Complex*>());
  }else{
    return Complex(coerce<double>(p), 0);
  }
}

bool is_numeric_type(Lisp_ptr p){
  switch(p.tag()){
  case Ptr_tag::integer:
  case Ptr_tag::rational:
  case Ptr_tag::real:
  case Ptr_tag::complex:
    return true;
  case Ptr_tag::undefined: case Ptr_tag::boolean:
  case Ptr_tag::character: case Ptr_tag::cons:
  case Ptr_tag::symbol:
  case Ptr_tag::i_procedure: case Ptr_tag::n_procedure:
  case Ptr_tag::continuation: case Ptr_tag::syntax_rules:
  case Ptr_tag::string:    case Ptr_tag::vector:
  case Ptr_tag::input_port: case Ptr_tag::output_port:
  case Ptr_tag::env:  case Ptr_tag::syntactic_closure:
  case Ptr_tag::vm_op: case Ptr_tag::vm_argcount:
  case Ptr_tag::notation:
  default:
    return false;
  }
}

bool is_numeric_convertible(Lisp_ptr p, Ptr_tag tag){
  switch(p.tag()){
  case Ptr_tag::integer:
    if(tag == Ptr_tag::integer) return true;
    // fall through
  case Ptr_tag::rational:
    if(tag == Ptr_tag::rational) return true;
    // fall through
  case Ptr_tag::real:
    if(tag == Ptr_tag::real) return true;
    // fall through
  case Ptr_tag::complex:
    return (tag == Ptr_tag::complex);
  case Ptr_tag::undefined: case Ptr_tag::boolean:
  case Ptr_tag::character: case Ptr_tag::cons:
  case Ptr_tag::symbol:
  case Ptr_tag::i_procedure: case Ptr_tag::n_procedure:
  case Ptr_tag::continuation: case Ptr_tag::syntax_rules:
  case Ptr_tag::string:    case Ptr_tag::vector:
  case Ptr_tag::input_port: case Ptr_tag::output_port:
  case Ptr_tag::env:  case Ptr_tag::syntactic_closure:
  case Ptr_tag::vm_op: case Ptr_tag::vm_argcount:
  case Ptr_tag::notation:
  default:
    return false;
  }
}

Lisp_ptr wrap_number(const Rational& q){
  if(q.is_convertible<int>()){
    return Lisp_ptr{static_cast<int>(q)};
  }else if(q.is_convertible<Rational>()){
    return {zs_new<Rational>(q)};
  }else{
    print_zs_warning("integer overflow occured. coerced into real.");
    return {zs_new<double>(static_cast<double>(q))};
  }
}

Lisp_ptr wrap_number(double d){
  return {zs_new<double>(d)};
}

Lisp_ptr wrap_number(const Complex& z){
  return {zs_new<Complex>(z)};
}

Lisp_ptr to_exact(Lisp_ptr p){
  switch(p.tag()){
  case Ptr_tag::integer:
  case Ptr_tag::rational:
    return p;
  case Ptr_tag::real:
    return wrap_number(static_cast<int>(*p.get<double*>()));
  case Ptr_tag::complex:
    throw_zs_error(p, "number error: conversion from complex to exact number is not supprted.\n");
  case Ptr_tag::undefined:
  case Ptr_tag::boolean:
  case Ptr_tag::character:
  case Ptr_tag::cons:
  case Ptr_tag::symbol:
  case Ptr_tag::i_procedure:
  case Ptr_tag::n_procedure:
  case Ptr_tag::continuation:
  case Ptr_tag::string:
  case Ptr_tag::vector:
  case Ptr_tag::input_port:
  case Ptr_tag::output_port:
  case Ptr_tag::env:
  case Ptr_tag::syntactic_closure:
  case Ptr_tag::syntax_rules:
  case Ptr_tag::vm_op:
  case Ptr_tag::vm_argcount:
  case Ptr_tag::notation:
  default:
    UNEXP_DEFAULT();
  }
}

Lisp_ptr to_inexact(Lisp_ptr p){
  switch(p.tag()){
  case Ptr_tag::integer:
  case Ptr_tag::rational:
    return wrap_number(coerce<double>(p));
  case Ptr_tag::real:
  case Ptr_tag::complex:
    return p;
  case Ptr_tag::undefined:
  case Ptr_tag::boolean:
  case Ptr_tag::character:
  case Ptr_tag::cons:
  case Ptr_tag::symbol:
  case Ptr_tag::i_procedure:
  case Ptr_tag::n_procedure:
  case Ptr_tag::continuation:
  case Ptr_tag::string:
  case Ptr_tag::vector:
  case Ptr_tag::input_port:
  case Ptr_tag::output_port:
  case Ptr_tag::env:
  case Ptr_tag::syntactic_closure:
  case Ptr_tag::syntax_rules:
  case Ptr_tag::vm_op:
  case Ptr_tag::vm_argcount:
  case Ptr_tag::notation:
  default:
    UNEXP_DEFAULT();
  }
}
<|endoftext|>


<commit_before><commit_msg>Updated FormattedString function to use precision argument.<commit_after><|endoftext|>


<commit_before>// Demonstrates atomically decrementing a counter in shared memory between
// multiple processes using boost named_mutex and interprocess APIs.
//
// To run:
// ./harness.o -num_processes 2 ./test.o
//
// Author: Sam Xi

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>

#include "mpkeys.h"

int main() {

  using namespace boost::interprocess;
  using namespace xiosim::shared;

  managed_shared_memory shm(open_or_create, XIOSIM_SHARED_MEMORY_KEY.c_str(),
      DEFAULT_SHARED_MEMORY_SIZE);
  std::cout << "Opened shared memory" << std::endl;
  named_mutex init_lock(open_only, XIOSIM_INIT_SHARED_LOCK.c_str());
  std::cout << "Opened lock" << std::endl;
  init_lock.lock();
  std::cout << "Lock acquired" << std::endl;

  int *counter = shm.find_or_construct<int>(XIOSIM_INIT_COUNTER_KEY.c_str())(0);
  std::cout << "Counter value is: " << *counter << std::endl;
  (*counter)--;
  init_lock.unlock();
  while (*counter > 0);
  std::cout << "COntinuing execution." << std::endl;

  return 0;
}
<commit_msg>Changed std::string to c strings<commit_after>// Demonstrates atomically decrementing a counter in shared memory between
// multiple processes using boost named_mutex and interprocess APIs.
//
// To run:
// ./harness.o -num_processes 2 ./test.o
//
// Author: Sam Xi

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>

#include "mpkeys.h"

int main() {

  using namespace boost::interprocess;
  using namespace xiosim::shared;

  managed_shared_memory shm(open_or_create, XIOSIM_SHARED_MEMORY_KEY,
      DEFAULT_SHARED_MEMORY_SIZE);
  std::cout << "Opened shared memory" << std::endl;
  named_mutex init_lock(open_only, XIOSIM_INIT_SHARED_LOCK);
  std::cout << "Opened lock" << std::endl;
  init_lock.lock();
  std::cout << "Lock acquired" << std::endl;

  int *counter = shm.find_or_construct<int>(XIOSIM_INIT_COUNTER_KEY)(0);
  std::cout << "Counter value is: " << *counter << std::endl;
  (*counter)--;
  init_lock.unlock();
  while (*counter > 0);
  std::cout << "COntinuing execution." << std::endl;

  return 0;
}
<|endoftext|>


<commit_before><commit_msg>fix msgs, add optional args to chain/wallet RPC-API additions<commit_after><|endoftext|>


<commit_before><commit_msg>Mark btf as depending on libbpf in --info<commit_after><|endoftext|>


<commit_before><commit_msg>Using MsgPack::select() to filter results<commit_after><|endoftext|>


<commit_before>/*
 * HttpEndPoint.cpp - Kurento Media Server
 *
 * Copyright (C) 2013 Kurento
 * Contact: Miguel París Díaz <mparisdiaz@gmail.com>
 * Contact: José Antonio Santos Cadenas <santoscadenas@kurento.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3
 * as published by the Free Software Foundation.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "HttpEndPoint.hpp"

namespace kurento
{

HttpEndPoint::HttpEndPoint (std::shared_ptr<MediaPipeline> parent) : EndPoint (parent)
{
  this->type.__set_endPoint (EndPointType::type::HTTP_END_POINT);
}

HttpEndPoint::~HttpEndPoint() throw ()
{
  this->url = "DUMMY URL";
}

std::string
HttpEndPoint::getUrl ()
{
  return url;
}

} // kurento
<commit_msg>Implement constructor and destructor for HttpEndPoint class<commit_after>/*
 * HttpEndPoint.cpp - Kurento Media Server
 *
 * Copyright (C) 2013 Kurento
 * Contact: Miguel París Díaz <mparisdiaz@gmail.com>
 * Contact: José Antonio Santos Cadenas <santoscadenas@kurento.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3
 * as published by the Free Software Foundation.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "HttpEndPoint.hpp"

namespace kurento
{

HttpEndPoint::HttpEndPoint (std::shared_ptr<MediaPipeline> parent) :
  EndPoint (parent)
{
  gchar *name;
  this->type.__set_endPoint (EndPointType::type::HTTP_END_POINT);

  name = getIdStr ();
  element = gst_element_factory_make ("httpendpoint", name);
  g_free (name);

  g_object_ref (element);
  gst_bin_add (GST_BIN (parent->pipeline), element);
  gst_element_sync_state_with_parent (element);
}

HttpEndPoint::~HttpEndPoint() throw ()
{
  gst_bin_remove (GST_BIN ( (
      (std::shared_ptr<MediaPipeline> &) parent)->pipeline), element);
  gst_element_set_state (element, GST_STATE_NULL);
  g_object_unref (element);
}

std::string
HttpEndPoint::getUrl ()
{
  return url;
}

} // kurento
<|endoftext|>


<commit_before>/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
 * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) 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. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *                                                                       *
 * 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 files    *
 * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
 *                                                                       *
 *************************************************************************/

#include <ode/ode.h>
#include <drawstuff/drawstuff.h>

#ifdef _MSC_VER
#pragma warning(disable:4244 4305)  // for VC++, no precision loss complaints
#endif

// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#endif

// some constants
#define SIDE (0.5f)	// side length of a box
#define MASS (1.0)	// mass of a box

// dynamics and collision objects
static dWorldID world;
static dBodyID body[2];
static dGeomID geom[2];
static dJointID lmotor[2];
static dJointID amotor[2];
static dSpaceID space;
static dJointGroupID contactgroup;

// start simulation - set viewpoint

static void start()
{
  static float xyz[3] = {1.0382f,-1.0811f,1.4700f};
  static float hpr[3] = {135.0000f,-19.5000f,0.0000f};
  dsSetViewpoint (xyz,hpr);
  printf ("Press 'q,a,z' to control one axis of lmotor connectiong two bodies. (q is +,a is 0, z is -)\n");
  printf ("Press 'w,e,r' to control one axis of lmotor connectiong first body with world. (w is +,e is 0, r is -)\n");
}

// called when a key pressed

static void command (int cmd)
{
  if (cmd == 'q' || cmd == 'Q') {
  	dJointSetLMotorParam(lmotor[0],dParamVel,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel3,0.1);
  } else if (cmd == 'a' || cmd == 'A') {
  	dJointSetLMotorParam(lmotor[0],dParamVel,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel3,0);
  } else if (cmd == 'z' || cmd == 'Z') {
  	dJointSetLMotorParam(lmotor[0],dParamVel,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel3,-0.1);
  } else if (cmd == 'w' || cmd == 'W') {
  	dJointSetLMotorParam(lmotor[1],dParamVel,0.1);
  	dJointSetLMotorParam(lmotor[1],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[1],dParamVel3,0);
  } else if (cmd == 'e' || cmd == 'E') {
  	dJointSetLMotorParam(lmotor[1],dParamVel,0);
  	dJointSetLMotorParam(lmotor[1],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[1],dParamVel3,0);
  } else if (cmd == 'r' || cmd == 'R') {
  	dJointSetLMotorParam(lmotor[1],dParamVel,-0.1);
  	dJointSetLMotorParam(lmotor[1],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[1],dParamVel3,0);
  }

}

static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
  // exit without doing anything if the two bodies are connected by a joint
  dBodyID b1 = dGeomGetBody(o1);
  dBodyID b2 = dGeomGetBody(o2);

  dContact contact;
  contact.surface.mode = 0;
  contact.surface.mu = dInfinity;
  if (dCollide (o1,o2,0,&contact.geom,sizeof(dContactGeom))) {
    dJointID c = dJointCreateContact (world,contactgroup,&contact);
    dJointAttach (c,b1,b2);
  }
}

// simulation loop

static void simLoop (int pause)
{
  if (!pause) {
    dSpaceCollide(space,0,&nearCallback);
    dWorldQuickStep (world,0.05);
	dJointGroupEmpty(contactgroup);
  }

  dReal sides1[3];
  dGeomBoxGetLengths(geom[0], sides1);
  dReal sides2[3];
  dGeomBoxGetLengths(geom[1], sides2);
  dsSetTexture (DS_WOOD);
  dsSetColor (1,1,0);
  dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides1);
  dsSetColor (0,1,1);
  dsDrawBox (dBodyGetPosition(body[1]),dBodyGetRotation(body[1]),sides2);
}

int main (int argc, char **argv)
{
  // setup pointers to drawstuff callback functions
  dsFunctions fn;
  fn.version = DS_VERSION;
  fn.start = &start;
  fn.step = &simLoop;
  fn.command = &command;
  fn.stop = 0;
  fn.path_to_textures = "../../drawstuff/textures";

  // create world
  contactgroup = dJointGroupCreate(0);
  world = dWorldCreate();
  space = dSimpleSpaceCreate(0);
  dMass m;
  dMassSetBox (&m,1,SIDE,SIDE,SIDE);
  dMassAdjust (&m,MASS);

  body[0] = dBodyCreate (world);
  dBodySetMass (body[0],&m);
  dBodySetPosition (body[0],0,0,1);
  geom[0] = dCreateBox(space,SIDE,SIDE,SIDE);
  body[1] = dBodyCreate (world);
  dBodySetMass (body[1],&m);
  dBodySetPosition (body[1],0,0,2);
  geom[1] = dCreateBox(space,SIDE,SIDE,SIDE);

  dGeomSetBody(geom[0],body[0]);
  dGeomSetBody(geom[1],body[1]);

  lmotor[0] = dJointCreateLMotor (world,0);
  dJointAttach (lmotor[0],body[0],body[1]);
  lmotor[1] = dJointCreateLMotor (world,0);
  dJointAttach (lmotor[1],body[0],0);
  amotor[0] = dJointCreateAMotor(world,0);
  dJointAttach(amotor[0], body[0],body[1]);
  amotor[1] = dJointCreateAMotor(world,0);
  dJointAttach(amotor[1], body[0], 0);

  for (int i=0; i<2; i++) {
	  dJointSetAMotorNumAxes(amotor[i], 3);
	  dJointSetAMotorAxis(amotor[i],0,1,1,0,0);
	  dJointSetAMotorAxis(amotor[i],1,1,0,1,0);
	  dJointSetAMotorAxis(amotor[i],2,1,0,0,1);
	  dJointSetAMotorParam(amotor[i],dParamFMax,0.00001);
	  dJointSetAMotorParam(amotor[i],dParamFMax2,0.00001);
	  dJointSetAMotorParam(amotor[i],dParamFMax3,0.00001);

	  dJointSetAMotorParam(amotor[i],dParamVel,0);
	  dJointSetAMotorParam(amotor[i],dParamVel2,0);
	  dJointSetAMotorParam(amotor[i],dParamVel3,0);

	  dJointSetLMotorNumAxes(lmotor[i],3);
	  dJointSetLMotorAxis(lmotor[i],0,1,1,0,0);
	  dJointSetLMotorAxis(lmotor[i],1,1,0,1,0);
	  dJointSetLMotorAxis(lmotor[i],2,1,0,0,1);

	  dJointSetLMotorParam(lmotor[i],dParamFMax,0.0001);
	  dJointSetLMotorParam(lmotor[i],dParamFMax2,0.0001);
	  dJointSetLMotorParam(lmotor[i],dParamFMax3,0.0001);
  }

  // run simulation
  dsSimulationLoop (argc,argv,352,288,&fn);

  dWorldDestroy (world);
  dSpaceDestroy (space);
  dJointGroupDestroy(contactgroup);
  return 0;
}
<commit_msg>accept a path to textures<commit_after>/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
 * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) 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. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *                                                                       *
 * 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 files    *
 * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
 *                                                                       *
 *************************************************************************/

#include <ode/ode.h>
#include <drawstuff/drawstuff.h>

#ifdef _MSC_VER
#pragma warning(disable:4244 4305)  // for VC++, no precision loss complaints
#endif

// select correct drawing functions
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#endif

// some constants
#define SIDE (0.5f)	// side length of a box
#define MASS (1.0)	// mass of a box

// dynamics and collision objects
static dWorldID world;
static dBodyID body[2];
static dGeomID geom[2];
static dJointID lmotor[2];
static dJointID amotor[2];
static dSpaceID space;
static dJointGroupID contactgroup;

// start simulation - set viewpoint

static void start()
{
  static float xyz[3] = {1.0382f,-1.0811f,1.4700f};
  static float hpr[3] = {135.0000f,-19.5000f,0.0000f};
  dsSetViewpoint (xyz,hpr);
  printf ("Press 'q,a,z' to control one axis of lmotor connectiong two bodies. (q is +,a is 0, z is -)\n");
  printf ("Press 'w,e,r' to control one axis of lmotor connectiong first body with world. (w is +,e is 0, r is -)\n");
}

// called when a key pressed

static void command (int cmd)
{
  if (cmd == 'q' || cmd == 'Q') {
  	dJointSetLMotorParam(lmotor[0],dParamVel,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel3,0.1);
  } else if (cmd == 'a' || cmd == 'A') {
  	dJointSetLMotorParam(lmotor[0],dParamVel,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel3,0);
  } else if (cmd == 'z' || cmd == 'Z') {
  	dJointSetLMotorParam(lmotor[0],dParamVel,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[0],dParamVel3,-0.1);
  } else if (cmd == 'w' || cmd == 'W') {
  	dJointSetLMotorParam(lmotor[1],dParamVel,0.1);
  	dJointSetLMotorParam(lmotor[1],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[1],dParamVel3,0);
  } else if (cmd == 'e' || cmd == 'E') {
  	dJointSetLMotorParam(lmotor[1],dParamVel,0);
  	dJointSetLMotorParam(lmotor[1],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[1],dParamVel3,0);
  } else if (cmd == 'r' || cmd == 'R') {
  	dJointSetLMotorParam(lmotor[1],dParamVel,-0.1);
  	dJointSetLMotorParam(lmotor[1],dParamVel2,0);
  	dJointSetLMotorParam(lmotor[1],dParamVel3,0);
  }

}

static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
  // exit without doing anything if the two bodies are connected by a joint
  dBodyID b1 = dGeomGetBody(o1);
  dBodyID b2 = dGeomGetBody(o2);

  dContact contact;
  contact.surface.mode = 0;
  contact.surface.mu = dInfinity;
  if (dCollide (o1,o2,0,&contact.geom,sizeof(dContactGeom))) {
    dJointID c = dJointCreateContact (world,contactgroup,&contact);
    dJointAttach (c,b1,b2);
  }
}

// simulation loop

static void simLoop (int pause)
{
  if (!pause) {
    dSpaceCollide(space,0,&nearCallback);
    dWorldQuickStep (world,0.05);
	dJointGroupEmpty(contactgroup);
  }

  dReal sides1[3];
  dGeomBoxGetLengths(geom[0], sides1);
  dReal sides2[3];
  dGeomBoxGetLengths(geom[1], sides2);
  dsSetTexture (DS_WOOD);
  dsSetColor (1,1,0);
  dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides1);
  dsSetColor (0,1,1);
  dsDrawBox (dBodyGetPosition(body[1]),dBodyGetRotation(body[1]),sides2);
}

int main (int argc, char **argv)
{
  // setup pointers to drawstuff callback functions
  dsFunctions fn;
  fn.version = DS_VERSION;
  fn.start = &start;
  fn.step = &simLoop;
  fn.command = &command;
  fn.stop = 0;
  fn.path_to_textures = "../../drawstuff/textures";
  if(argc>=2)
  {
    fn.path_to_textures = argv[1];
  }

  // create world
  contactgroup = dJointGroupCreate(0);
  world = dWorldCreate();
  space = dSimpleSpaceCreate(0);
  dMass m;
  dMassSetBox (&m,1,SIDE,SIDE,SIDE);
  dMassAdjust (&m,MASS);

  body[0] = dBodyCreate (world);
  dBodySetMass (body[0],&m);
  dBodySetPosition (body[0],0,0,1);
  geom[0] = dCreateBox(space,SIDE,SIDE,SIDE);
  body[1] = dBodyCreate (world);
  dBodySetMass (body[1],&m);
  dBodySetPosition (body[1],0,0,2);
  geom[1] = dCreateBox(space,SIDE,SIDE,SIDE);

  dGeomSetBody(geom[0],body[0]);
  dGeomSetBody(geom[1],body[1]);

  lmotor[0] = dJointCreateLMotor (world,0);
  dJointAttach (lmotor[0],body[0],body[1]);
  lmotor[1] = dJointCreateLMotor (world,0);
  dJointAttach (lmotor[1],body[0],0);
  amotor[0] = dJointCreateAMotor(world,0);
  dJointAttach(amotor[0], body[0],body[1]);
  amotor[1] = dJointCreateAMotor(world,0);
  dJointAttach(amotor[1], body[0], 0);

  for (int i=0; i<2; i++) {
	  dJointSetAMotorNumAxes(amotor[i], 3);
	  dJointSetAMotorAxis(amotor[i],0,1,1,0,0);
	  dJointSetAMotorAxis(amotor[i],1,1,0,1,0);
	  dJointSetAMotorAxis(amotor[i],2,1,0,0,1);
	  dJointSetAMotorParam(amotor[i],dParamFMax,0.00001);
	  dJointSetAMotorParam(amotor[i],dParamFMax2,0.00001);
	  dJointSetAMotorParam(amotor[i],dParamFMax3,0.00001);

	  dJointSetAMotorParam(amotor[i],dParamVel,0);
	  dJointSetAMotorParam(amotor[i],dParamVel2,0);
	  dJointSetAMotorParam(amotor[i],dParamVel3,0);

	  dJointSetLMotorNumAxes(lmotor[i],3);
	  dJointSetLMotorAxis(lmotor[i],0,1,1,0,0);
	  dJointSetLMotorAxis(lmotor[i],1,1,0,1,0);
	  dJointSetLMotorAxis(lmotor[i],2,1,0,0,1);

	  dJointSetLMotorParam(lmotor[i],dParamFMax,0.0001);
	  dJointSetLMotorParam(lmotor[i],dParamFMax2,0.0001);
	  dJointSetLMotorParam(lmotor[i],dParamFMax3,0.0001);
  }

  // run simulation
  dsSimulationLoop (argc,argv,352,288,&fn);

  dWorldDestroy (world);
  dSpaceDestroy (space);
  dJointGroupDestroy(contactgroup);
  return 0;
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "query_pagers.hh"
#include "query_pager.hh"
#include "cql3/selection/selection.hh"
#include "log.hh"
#include "service/storage_proxy.hh"
#include "to_string.hh"

static logging::logger qlogger("paging");

class service::pager::query_pagers::impl : public query_pager {
public:
    impl(schema_ptr s, ::shared_ptr<cql3::selection::selection> selection,
                    service::query_state& state,
                    const cql3::query_options& options,
                    lw_shared_ptr<query::read_command> cmd,
                    dht::partition_range_vector ranges)
                    : _has_clustering_keys(has_clustering_keys(*s, *cmd))
                    , _max(cmd->row_limit)
                    , _schema(std::move(s))
                    , _selection(selection)
                    , _state(state)
                    , _options(options)
                    , _cmd(std::move(cmd))
                    , _ranges(std::move(ranges))
    {}

private:
    static bool has_clustering_keys(const schema& s, const query::read_command& cmd) {
        return s.clustering_key_size() > 0
               && !cmd.slice.options.contains<query::partition_slice::option::distinct>();
    }

    future<> fetch_page(cql3::selection::result_set_builder& builder, uint32_t page_size, gc_clock::time_point now) override {
        auto state = _options.get_paging_state();

        if (!_last_pkey && state) {
            _max = state->get_remaining();
            _last_pkey = state->get_partition_key();
            _last_ckey = state->get_clustering_key();
            _cmd->query_uuid = state->get_query_uuid();
            _cmd->is_first_page = false;
        } else {
            // Reusing readers is currently only supported for singular queries.
            if (_ranges.front().is_singular()) {
                _cmd->query_uuid = utils::make_random_uuid();
            }
            _cmd->is_first_page = true;
        }
        qlogger.trace("fetch_page query id {}", _cmd->query_uuid);

        if (_last_pkey) {
            auto dpk = dht::global_partitioner().decorate_key(*_schema, *_last_pkey);
            dht::ring_position lo(dpk);

            auto reversed = _cmd->slice.options.contains<query::partition_slice::option::reversed>();

            qlogger.trace("PKey={}, CKey={}, reversed={}", dpk, _last_ckey, reversed);

            // Note: we're assuming both that the ranges are checked
            // and "cql-compliant", and that storage_proxy will process
            // the ranges in order
            //
            // If the original query has singular restrictions like "col in (x, y, z)",
            // we will eventually generate an empty range. This is ok, because empty range == nothing,
            // which is what we thus mean.
            auto modify_ranges = [reversed](auto& ranges, auto& lo, bool inclusive, const auto& cmp) {
                typedef typename std::remove_reference_t<decltype(ranges)>::value_type range_type;
                typedef typename range_type::bound bound_type;
                bool found = false;

                auto i = ranges.begin();
                while (i != ranges.end()) {
                    bool contains = i->contains(lo, cmp);

                    if (contains) {
                        found = true;
                    }

                    bool remove = !found
                            || (contains && !inclusive && (i->is_singular()
                                || (reversed && i->start() && !cmp(i->start()->value(), lo))
                                || (!reversed && i->end() && !cmp(i->end()->value(), lo))))
                            ;

                    if (remove) {
                        qlogger.trace("Remove range {}", *i);
                        i = ranges.erase(i);
                        continue;
                    }
                    if (contains) {
                        auto r = reversed && !i->is_singular()
                                ? range_type(i->start(), bound_type{ lo, inclusive })
                                : range_type( bound_type{ lo, inclusive }, i->end(), i->is_singular())
                                ;
                        qlogger.trace("Modify range {} -> {}", *i, r);
                        *i = std::move(r);
                    }
                    ++i;
                }
                qlogger.trace("Result ranges {}", ranges);
            };

            // Because of #1446 we don't have a comparator to use with
            // range<clustering_key_prefix> which would produce correct results.
            // This means we cannot reuse the same logic for dealing with
            // partition and clustering keys.
            auto modify_ck_ranges = [reversed] (const schema& s, auto& ranges, auto& lo) {
                typedef typename std::remove_reference_t<decltype(ranges)>::value_type range_type;
                typedef typename range_type::bound bound_type;

                auto cmp = [reversed, bv_cmp = bound_view::compare(s)] (const auto& a, const auto& b) {
                    return reversed ? bv_cmp(b, a) : bv_cmp(a, b);
                };
                auto start_bound = [reversed] (const auto& range) -> const bound_view& {
                    return reversed ? range.second : range.first;
                };
                auto end_bound = [reversed] (const auto& range) -> const bound_view& {
                    return reversed ? range.first : range.second;
                };
                clustering_key_prefix::equality eq(s);

                auto it = ranges.begin();
                while (it != ranges.end()) {
                    auto range = bound_view::from_range(*it);
                    if (cmp(end_bound(range), lo) || eq(end_bound(range).prefix, lo)) {
                        qlogger.trace("Remove ck range {}", *it);
                        it = ranges.erase(it);
                        continue;
                    } else if (cmp(start_bound(range), lo)) {
                        assert(cmp(lo, end_bound(range)));
                        auto r = reversed ? range_type(it->start(), bound_type { lo, false })
                                          : range_type(bound_type { lo, false }, it->end());
                        qlogger.trace("Modify ck range {} -> {}", *it, r);
                        *it = std::move(r);
                    }
                    ++it;
                }
            };

            // last ck can be empty depending on whether we
            // deserialized state or not. This case means "last page ended on
            // something-not-bound-by-clustering" (i.e. a static row, alone)
            const bool has_ck = _has_clustering_keys && _last_ckey;

            // If we have no clustering keys, it should mean we only have one row
            // per PK. Thus we can just bypass the last one.
            modify_ranges(_ranges, lo, has_ck, dht::ring_position_comparator(*_schema));

            if (has_ck) {
                query::clustering_row_ranges row_ranges = _cmd->slice.default_row_ranges();
                clustering_key_prefix ckp = clustering_key_prefix::from_exploded(*_schema, _last_ckey->explode(*_schema));
                modify_ck_ranges(*_schema, row_ranges, ckp);

                _cmd->slice.set_range(*_schema, *_last_pkey, row_ranges);
            }
        }

        auto max_rows = std::min(_max, page_size);

        // We always need PK so we can determine where to start next.
        _cmd->slice.options.set<query::partition_slice::option::send_partition_key>();
        // don't add empty bytes (cks) unless we have to
        if (_has_clustering_keys) {
            _cmd->slice.options.set<
                    query::partition_slice::option::send_clustering_key>();
        }
        _cmd->row_limit = max_rows;

        qlogger.debug("Fetching {}, page size={}, max_rows={}",
                _cmd->cf_id, page_size, max_rows
                );

        auto ranges = _ranges;
        auto command = ::make_lw_shared<query::read_command>(*_cmd);
        return get_local_storage_proxy().query(_schema, std::move(command), std::move(ranges),
                _options.get_consistency(), _state.get_trace_state()).then(
                [this, &builder, page_size, now](foreign_ptr<lw_shared_ptr<query::result>> results, paging_state::replicas_per_token_range) {
                    handle_result(builder, std::move(results), page_size, now);
                });
    }

    future<std::unique_ptr<cql3::result_set>> fetch_page(uint32_t page_size,
            gc_clock::time_point now) override {
        return do_with(
                cql3::selection::result_set_builder(*_selection, now,
                        _options.get_cql_serialization_format()),
                [this, page_size, now](auto& builder) {
                    return this->fetch_page(builder, page_size, now).then([&builder] {
                       return builder.build();
                    });
                });
    }

    void handle_result(
            cql3::selection::result_set_builder& builder,
            foreign_ptr<lw_shared_ptr<query::result>> results,
            uint32_t page_size, gc_clock::time_point now) {

        class myvisitor : public cql3::selection::result_set_builder::visitor {
        public:
            uint32_t total_rows = 0;
            std::experimental::optional<partition_key> last_pkey;
            std::experimental::optional<clustering_key> last_ckey;

            myvisitor(cql3::selection::result_set_builder& builder,
                    const schema& s,
                    const cql3::selection::selection& selection)
                    : visitor(builder, s, selection) {
            }

            void accept_new_partition(uint32_t) {
                throw std::logic_error("Should not reach!");
            }
            void accept_new_partition(const partition_key& key, uint32_t row_count) {
                qlogger.trace("Accepting partition: {} ({})", key, row_count);
                total_rows += std::max(row_count, 1u);
                last_pkey = key;
                last_ckey = { };
                visitor::accept_new_partition(key, row_count);
            }
            void accept_new_row(const clustering_key& key,
                    const query::result_row_view& static_row,
                    const query::result_row_view& row) {
                last_ckey = key;
                visitor::accept_new_row(key, static_row, row);
            }
            void accept_new_row(const query::result_row_view& static_row,
                    const query::result_row_view& row) {
                visitor::accept_new_row(static_row, row);
            }
            void accept_partition_end(const query::result_row_view& static_row) {
                visitor::accept_partition_end(static_row);
            }
        };

        myvisitor v(builder, *_schema, *_selection);
        query::result_view::consume(*results, _cmd->slice, v);

        if (_last_pkey) {
            // refs #752, when doing aggregate queries we will re-use same
            // slice repeatedly. Since "specific ck ranges" only deal with
            // a single extra range, we must clear out the old one
            // Even if it was not so of course, leaving junk in the slice
            // is bad.
            _cmd->slice.clear_range(*_schema, *_last_pkey);
        }

        _max = _max - v.total_rows;
        _exhausted = (v.total_rows < page_size && !results->is_short_read()) || _max == 0;
        _last_pkey = v.last_pkey;
        _last_ckey = v.last_ckey;

        qlogger.debug("Fetched {} rows, max_remain={} {}", v.total_rows, _max, _exhausted ? "(exh)" : "");

        if (_last_pkey) {
            qlogger.debug("Last partition key: {}", *_last_pkey);
        }
        if (_has_clustering_keys && _last_ckey) {
            qlogger.debug("Last clustering key: {}", *_last_ckey);
        }
    }

    bool is_exhausted() const override {
        return _exhausted;
    }

    int max_remaining() const override {
        return _max;
    }

    ::shared_ptr<const service::pager::paging_state> state() const override {
        return _exhausted ?  nullptr : ::make_shared<const paging_state>(*_last_pkey,
                _last_ckey, _max, _cmd->query_uuid, paging_state::replicas_per_token_range{});
    }

private:
    // remember if we use clustering. if not, each partition == one row
    const bool _has_clustering_keys;
    bool _exhausted = false;
    uint32_t _max;

    std::experimental::optional<partition_key> _last_pkey;
    std::experimental::optional<clustering_key> _last_ckey;

    schema_ptr _schema;
    ::shared_ptr<cql3::selection::selection> _selection;
    service::query_state& _state;
    const cql3::query_options& _options;
    lw_shared_ptr<query::read_command> _cmd;
    dht::partition_range_vector _ranges;
};

bool service::pager::query_pagers::may_need_paging(uint32_t page_size,
        const query::read_command& cmd,
        const dht::partition_range_vector& ranges) {
    auto est_max_rows =
            [&] {
                if (ranges.empty()) {
                    return cmd.row_limit;
                }
                uint32_t n = 0;
                for (auto& r : ranges) {
                    if (r.is_singular() && cmd.slice.options.contains<query::partition_slice::option::distinct>()) {
                        ++n;
                        continue;
                    }
                    return cmd.row_limit;
                }
                return n;
            };

    auto est = est_max_rows();
    auto need_paging = est > page_size;

    qlogger.debug("Query of {}, page_size={}, limit={} {}", cmd.cf_id, page_size,
                    cmd.row_limit,
                    need_paging ? "requires paging" : "does not require paging");

    return need_paging;
}

::shared_ptr<service::pager::query_pager> service::pager::query_pagers::pager(
        schema_ptr s, ::shared_ptr<cql3::selection::selection> selection,
        service::query_state& state, const cql3::query_options& options,
        lw_shared_ptr<query::read_command> cmd,
        dht::partition_range_vector ranges) {
    return ::make_shared<impl>(std::move(s), std::move(selection), state,
            options, std::move(cmd), std::move(ranges));
}

<commit_msg>Use the last_replicas stored in the page_state<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "query_pagers.hh"
#include "query_pager.hh"
#include "cql3/selection/selection.hh"
#include "log.hh"
#include "service/storage_proxy.hh"
#include "to_string.hh"

static logging::logger qlogger("paging");

class service::pager::query_pagers::impl : public query_pager {
public:
    impl(schema_ptr s, ::shared_ptr<cql3::selection::selection> selection,
                    service::query_state& state,
                    const cql3::query_options& options,
                    lw_shared_ptr<query::read_command> cmd,
                    dht::partition_range_vector ranges)
                    : _has_clustering_keys(has_clustering_keys(*s, *cmd))
                    , _max(cmd->row_limit)
                    , _schema(std::move(s))
                    , _selection(selection)
                    , _state(state)
                    , _options(options)
                    , _cmd(std::move(cmd))
                    , _ranges(std::move(ranges))
    {}

private:
    static bool has_clustering_keys(const schema& s, const query::read_command& cmd) {
        return s.clustering_key_size() > 0
               && !cmd.slice.options.contains<query::partition_slice::option::distinct>();
    }

    future<> fetch_page(cql3::selection::result_set_builder& builder, uint32_t page_size, gc_clock::time_point now) override {
        auto state = _options.get_paging_state();

        if (!_last_pkey && state) {
            _max = state->get_remaining();
            _last_pkey = state->get_partition_key();
            _last_ckey = state->get_clustering_key();
            _cmd->query_uuid = state->get_query_uuid();
            _cmd->is_first_page = false;
            _last_replicas = state->get_last_replicas();
        } else {
            // Reusing readers is currently only supported for singular queries.
            if (_ranges.front().is_singular()) {
                _cmd->query_uuid = utils::make_random_uuid();
            }
            _cmd->is_first_page = true;
        }
        qlogger.trace("fetch_page query id {}", _cmd->query_uuid);

        if (_last_pkey) {
            auto dpk = dht::global_partitioner().decorate_key(*_schema, *_last_pkey);
            dht::ring_position lo(dpk);

            auto reversed = _cmd->slice.options.contains<query::partition_slice::option::reversed>();

            qlogger.trace("PKey={}, CKey={}, reversed={}", dpk, _last_ckey, reversed);

            // Note: we're assuming both that the ranges are checked
            // and "cql-compliant", and that storage_proxy will process
            // the ranges in order
            //
            // If the original query has singular restrictions like "col in (x, y, z)",
            // we will eventually generate an empty range. This is ok, because empty range == nothing,
            // which is what we thus mean.
            auto modify_ranges = [reversed](auto& ranges, auto& lo, bool inclusive, const auto& cmp) {
                typedef typename std::remove_reference_t<decltype(ranges)>::value_type range_type;
                typedef typename range_type::bound bound_type;
                bool found = false;

                auto i = ranges.begin();
                while (i != ranges.end()) {
                    bool contains = i->contains(lo, cmp);

                    if (contains) {
                        found = true;
                    }

                    bool remove = !found
                            || (contains && !inclusive && (i->is_singular()
                                || (reversed && i->start() && !cmp(i->start()->value(), lo))
                                || (!reversed && i->end() && !cmp(i->end()->value(), lo))))
                            ;

                    if (remove) {
                        qlogger.trace("Remove range {}", *i);
                        i = ranges.erase(i);
                        continue;
                    }
                    if (contains) {
                        auto r = reversed && !i->is_singular()
                                ? range_type(i->start(), bound_type{ lo, inclusive })
                                : range_type( bound_type{ lo, inclusive }, i->end(), i->is_singular())
                                ;
                        qlogger.trace("Modify range {} -> {}", *i, r);
                        *i = std::move(r);
                    }
                    ++i;
                }
                qlogger.trace("Result ranges {}", ranges);
            };

            // Because of #1446 we don't have a comparator to use with
            // range<clustering_key_prefix> which would produce correct results.
            // This means we cannot reuse the same logic for dealing with
            // partition and clustering keys.
            auto modify_ck_ranges = [reversed] (const schema& s, auto& ranges, auto& lo) {
                typedef typename std::remove_reference_t<decltype(ranges)>::value_type range_type;
                typedef typename range_type::bound bound_type;

                auto cmp = [reversed, bv_cmp = bound_view::compare(s)] (const auto& a, const auto& b) {
                    return reversed ? bv_cmp(b, a) : bv_cmp(a, b);
                };
                auto start_bound = [reversed] (const auto& range) -> const bound_view& {
                    return reversed ? range.second : range.first;
                };
                auto end_bound = [reversed] (const auto& range) -> const bound_view& {
                    return reversed ? range.first : range.second;
                };
                clustering_key_prefix::equality eq(s);

                auto it = ranges.begin();
                while (it != ranges.end()) {
                    auto range = bound_view::from_range(*it);
                    if (cmp(end_bound(range), lo) || eq(end_bound(range).prefix, lo)) {
                        qlogger.trace("Remove ck range {}", *it);
                        it = ranges.erase(it);
                        continue;
                    } else if (cmp(start_bound(range), lo)) {
                        assert(cmp(lo, end_bound(range)));
                        auto r = reversed ? range_type(it->start(), bound_type { lo, false })
                                          : range_type(bound_type { lo, false }, it->end());
                        qlogger.trace("Modify ck range {} -> {}", *it, r);
                        *it = std::move(r);
                    }
                    ++it;
                }
            };

            // last ck can be empty depending on whether we
            // deserialized state or not. This case means "last page ended on
            // something-not-bound-by-clustering" (i.e. a static row, alone)
            const bool has_ck = _has_clustering_keys && _last_ckey;

            // If we have no clustering keys, it should mean we only have one row
            // per PK. Thus we can just bypass the last one.
            modify_ranges(_ranges, lo, has_ck, dht::ring_position_comparator(*_schema));

            if (has_ck) {
                query::clustering_row_ranges row_ranges = _cmd->slice.default_row_ranges();
                clustering_key_prefix ckp = clustering_key_prefix::from_exploded(*_schema, _last_ckey->explode(*_schema));
                modify_ck_ranges(*_schema, row_ranges, ckp);

                _cmd->slice.set_range(*_schema, *_last_pkey, row_ranges);
            }
        }

        auto max_rows = std::min(_max, page_size);

        // We always need PK so we can determine where to start next.
        _cmd->slice.options.set<query::partition_slice::option::send_partition_key>();
        // don't add empty bytes (cks) unless we have to
        if (_has_clustering_keys) {
            _cmd->slice.options.set<
                    query::partition_slice::option::send_clustering_key>();
        }
        _cmd->row_limit = max_rows;

        qlogger.debug("Fetching {}, page size={}, max_rows={}",
                _cmd->cf_id, page_size, max_rows
                );

        auto ranges = _ranges;
        auto command = ::make_lw_shared<query::read_command>(*_cmd);
        auto& sp = get_local_storage_proxy();
        return sp.query(_schema, std::move(command), std::move(ranges),
                _options.get_consistency(), _state.get_trace_state(), sp.default_query_timeout(), std::move(_last_replicas)).then(
                [this, &builder, page_size, now](foreign_ptr<lw_shared_ptr<query::result>> results, paging_state::replicas_per_token_range last_replicas) {
                    _last_replicas = std::move(last_replicas);
                    handle_result(builder, std::move(results), page_size, now);
                });
    }

    future<std::unique_ptr<cql3::result_set>> fetch_page(uint32_t page_size,
            gc_clock::time_point now) override {
        return do_with(
                cql3::selection::result_set_builder(*_selection, now,
                        _options.get_cql_serialization_format()),
                [this, page_size, now](auto& builder) {
                    return this->fetch_page(builder, page_size, now).then([&builder] {
                       return builder.build();
                    });
                });
    }

    void handle_result(
            cql3::selection::result_set_builder& builder,
            foreign_ptr<lw_shared_ptr<query::result>> results,
            uint32_t page_size, gc_clock::time_point now) {

        class myvisitor : public cql3::selection::result_set_builder::visitor {
        public:
            uint32_t total_rows = 0;
            std::experimental::optional<partition_key> last_pkey;
            std::experimental::optional<clustering_key> last_ckey;

            myvisitor(cql3::selection::result_set_builder& builder,
                    const schema& s,
                    const cql3::selection::selection& selection)
                    : visitor(builder, s, selection) {
            }

            void accept_new_partition(uint32_t) {
                throw std::logic_error("Should not reach!");
            }
            void accept_new_partition(const partition_key& key, uint32_t row_count) {
                qlogger.trace("Accepting partition: {} ({})", key, row_count);
                total_rows += std::max(row_count, 1u);
                last_pkey = key;
                last_ckey = { };
                visitor::accept_new_partition(key, row_count);
            }
            void accept_new_row(const clustering_key& key,
                    const query::result_row_view& static_row,
                    const query::result_row_view& row) {
                last_ckey = key;
                visitor::accept_new_row(key, static_row, row);
            }
            void accept_new_row(const query::result_row_view& static_row,
                    const query::result_row_view& row) {
                visitor::accept_new_row(static_row, row);
            }
            void accept_partition_end(const query::result_row_view& static_row) {
                visitor::accept_partition_end(static_row);
            }
        };

        myvisitor v(builder, *_schema, *_selection);
        query::result_view::consume(*results, _cmd->slice, v);

        if (_last_pkey) {
            // refs #752, when doing aggregate queries we will re-use same
            // slice repeatedly. Since "specific ck ranges" only deal with
            // a single extra range, we must clear out the old one
            // Even if it was not so of course, leaving junk in the slice
            // is bad.
            _cmd->slice.clear_range(*_schema, *_last_pkey);
        }

        _max = _max - v.total_rows;
        _exhausted = (v.total_rows < page_size && !results->is_short_read()) || _max == 0;
        _last_pkey = v.last_pkey;
        _last_ckey = v.last_ckey;

        qlogger.debug("Fetched {} rows, max_remain={} {}", v.total_rows, _max, _exhausted ? "(exh)" : "");

        if (_last_pkey) {
            qlogger.debug("Last partition key: {}", *_last_pkey);
        }
        if (_has_clustering_keys && _last_ckey) {
            qlogger.debug("Last clustering key: {}", *_last_ckey);
        }
    }

    bool is_exhausted() const override {
        return _exhausted;
    }

    int max_remaining() const override {
        return _max;
    }

    ::shared_ptr<const service::pager::paging_state> state() const override {
        return _exhausted ?  nullptr : ::make_shared<const paging_state>(*_last_pkey,
                _last_ckey, _max, _cmd->query_uuid, _last_replicas);
    }

private:
    // remember if we use clustering. if not, each partition == one row
    const bool _has_clustering_keys;
    bool _exhausted = false;
    uint32_t _max;

    std::experimental::optional<partition_key> _last_pkey;
    std::experimental::optional<clustering_key> _last_ckey;

    schema_ptr _schema;
    ::shared_ptr<cql3::selection::selection> _selection;
    service::query_state& _state;
    const cql3::query_options& _options;
    lw_shared_ptr<query::read_command> _cmd;
    dht::partition_range_vector _ranges;
    paging_state::replicas_per_token_range _last_replicas;
};

bool service::pager::query_pagers::may_need_paging(uint32_t page_size,
        const query::read_command& cmd,
        const dht::partition_range_vector& ranges) {
    auto est_max_rows =
            [&] {
                if (ranges.empty()) {
                    return cmd.row_limit;
                }
                uint32_t n = 0;
                for (auto& r : ranges) {
                    if (r.is_singular() && cmd.slice.options.contains<query::partition_slice::option::distinct>()) {
                        ++n;
                        continue;
                    }
                    return cmd.row_limit;
                }
                return n;
            };

    auto est = est_max_rows();
    auto need_paging = est > page_size;

    qlogger.debug("Query of {}, page_size={}, limit={} {}", cmd.cf_id, page_size,
                    cmd.row_limit,
                    need_paging ? "requires paging" : "does not require paging");

    return need_paging;
}

::shared_ptr<service::pager::query_pager> service::pager::query_pagers::pager(
        schema_ptr s, ::shared_ptr<cql3::selection::selection> selection,
        service::query_state& state, const cql3::query_options& options,
        lw_shared_ptr<query::read_command> cmd,
        dht::partition_range_vector ranges) {
    return ::make_shared<impl>(std::move(s), std::move(selection), state,
            options, std::move(cmd), std::move(ranges));
}

<|endoftext|>