<commit_before>// select_flow.C --- Flows in and out of a volume.
//
// Copyright 2006 KVL and Per Abrahamsen
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#define BUILD_DLL
#include "select_value.h"
#include "block.h"
#include "alist.h"
#include "volume.h"
#include "border.h"
#include "geometry.h"
#include "treelog.h"
#include "librarian.h"
#ifdef DEBUG_EDGES
#include <sstream>
#endif

class SelectFlow : public SelectValue
{
  // Content.
private:

  const bool density;
  std::auto_ptr<Volume> volume;
  const Geometry* last_geo;
  std::vector<size_t> edges;
  std::vector<double> weight;

  // Use.
protected:
  virtual bool use_edge (const Geometry&, int out, int in) const = 0;

  // Output routines.
private:
  void output_array (const std::vector<double>&,
                     const Geometry*, const Soil*, const Vegetation*, Treelog&);

  // Create and Destroy.
private:
  symbol default_dimension (const symbol spec_dim) const;
  bool initialize (const Volume& volume,
		   const std::string& timestep, Treelog& msg);
  bool check_border (const Border& border,
                     const Volume& default_volume,
                     Treelog& msg) const;
public:
  static void load_syntax (Syntax& syntax, AttributeList& alist);
  SelectFlow (Block&);
};

void
SelectFlow::load_syntax (Syntax& syntax, AttributeList& alist)
{
  SelectValue::load_syntax (syntax, alist);
  syntax.add ("density", Syntax::Boolean, Syntax::Const,
              "If true, divide value with volume height.");
  alist.add ("density", false);
  syntax.add_object ("volume", Volume::component,
                     Syntax::Const, Syntax::Singleton,
                     "Soil volume to log flow into.");
  alist.add ("volume", Volume::infinite_box ());
}

symbol
SelectFlow::default_dimension (const symbol spec_dim) const
{
  if (density)
    return spec_dim;

  return Units::multiply (spec_dim, Units::cm2 ());
}

bool
SelectFlow::initialize (const Volume& default_volume,
                        const std::string& timestep, Treelog& msg)
{
  bool ok = true;

  if (!Select::initialize (default_volume, timestep, msg))
    ok = false;

  if (!volume->limit (default_volume, msg))
    ok = false;

  return ok;
}

bool
SelectFlow::check_border (const Border& border, const Volume& default_volume,
                          Treelog& msg) const
{ return volume->check_border (border, default_volume, msg); }

void
SelectFlow::output_array (const std::vector<double>& array,
                          const Geometry* geo, const Soil*, const Vegetation*,
			  Treelog& msg)
{
  if (geo != last_geo)
    {
      Treelog::Open nest (msg, name);
      last_geo = geo;
      const size_t size = geo->edge_size ();
      edges.clear ();
      weight.clear ();
      double total_area = 0.0;
      for (size_t e = 0; e < size; e++)
        {
          const int from = geo->edge_from (e);
          const bool from_inside = geo->node_center_in_volume (from, *volume);
          const int to = geo->edge_to (e);
          const bool to_inside = geo->node_center_in_volume (to, *volume);
          if (from_inside)
            {
              if (to_inside)
                // Both inside volume, don't use.
                continue;
              if (!use_edge (*geo, to, from))
                continue;
            }
          else
            {
              if (!to_inside)
                // Both outside volume, don't use.
                continue;
              if (!use_edge (*geo, from, to))
                continue;
            }
          edges.push_back (e);
          double area = geo->edge_area (e);
          total_area += area;
          if (from_inside)
            // Positive inwards.
            area *= -1;
          weight.push_back (area);
        }
      if (weight.size () ==0)
        msg.warning ("No edges found");
      else
        daisy_assert (std::isnormal (total_area));

      if (density)
        for (size_t i = 0; i < weight.size (); i++)
          weight[i] /= total_area;
#ifdef DEBUG_EDGES
      std::ostringstream tmp;
      tmp << "Total area: " << total_area << ", density = " << density
          << ", #edges = " << edges.size ();
      for (size_t i = 0; i < edges.size (); i++)
        tmp << "\n" << geo->edge_name (edges[i]) << ": weigth " << weight[i];
      msg.message (tmp.str ());
#endif
      daisy_assert (edges.size () == weight.size ());
    }
  daisy_assert (edges.size () <= array.size ());

  double sum = 0.0;
  for (size_t i = 0; i < edges.size (); i++)
    sum += array[edges[i]] * weight[i];

  add_result (sum);
}

SelectFlow::SelectFlow (Block& al)
  : SelectValue (al),
    density (al.flag ("density")),
    volume (Volume::build_obsolete (al)),
    last_geo (NULL)
{ }

struct SelectFlowTop : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_above)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_z (outside) > geo.cell_z (inside);
  }

  // Create and Destroy.
  SelectFlowTop (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowTopSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowTop (al); }

  SelectFlowTopSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from top of specified volume.");
    SelectFlow::load_syntax (syntax, alist);
    syntax.add ("from", "cm", Syntax::OptionalConst,
		"Specify height (negative) to measure from.\n\
By default, measure from the top.\n\
OBSOLETE: Use (volume box (top FROM)) instead.");

    Librarian::add_type (Select::component, "flow_top", alist, syntax, &make);
  }
} Select_flow_top_syntax;

static struct SelectFluxTopSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowTop (al); }

  SelectFluxTopSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Flux leaving top of specified volume.\n\
OBSOLETE: Use '(flow_top (negate true) (density true))' instead.");
    SelectFlow::load_syntax (syntax, alist);
    syntax.add ("from", "cm", Syntax::OptionalConst,
		"Specify height (negative) to measure from.\n\
By default, measure from the top.\n\
OBSOLETE: Use (volume box (top FROM)) instead.");
    alist.add ("density", true);
    Librarian::add_type (Select::component, "flux_top", alist, syntax, &make);
  }
} Select_flux_top_syntax;

struct SelectFlowBottom : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_below)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_z (outside) < geo.cell_z (inside);
  }

  // Create and Destroy.
  SelectFlowBottom (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowBottomSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowBottom (al); }

  SelectFlowBottomSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from bottom of specified volume.");
    SelectFlow::load_syntax (syntax, alist);
    syntax.add ("to", "cm", Syntax::OptionalConst,
		"Specify height (negative) to measure interval.\n\
By default, measure to the bottom.\n\
OBSOLETE: Use (volume box (bottom TO)) instead.");

    Librarian::add_type (Select::component, "flow_bottom", alist, syntax, &make);
  }
} Select_flow_bottom_syntax;

static struct SelectFluxBottomSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowBottom (al); }

  SelectFluxBottomSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Flux entering bottom of specified volume.\n\
OBSOLETE: Use '(flow_bottom (density true))' instead.");
    SelectFlow::load_syntax (syntax, alist);
    syntax.add ("to", "cm", Syntax::OptionalConst,
		"Specify height (negative) to measure to.\n\
By default, measure from the bottom.\n\
OBSOLETE: Use (volume box (bottom TO)) instead.");
    alist.add ("density", true);
    Librarian::add_type (Select::component, "flux_bottom", alist, syntax, &make);
  }
} Select_flux_bottom_syntax;

struct SelectFlowLeft : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_left)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_x (outside) < geo.cell_x (inside);
  }

  // Create and Destroy.
  SelectFlowLeft (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowLeftSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowLeft (al); }

  SelectFlowLeftSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from left of specified volume.");
    SelectFlow::load_syntax (syntax, alist);

    Librarian::add_type (Select::component, "flow_left", alist, syntax, &make);
  }
} Select_flow_left_syntax;

struct SelectFlowRight : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_right)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_x (outside) > geo.cell_x (inside);
  }

  // Create and Destroy.
  SelectFlowRight (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowRightSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowRight (al); }

  SelectFlowRightSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from right of specified volume.");
    SelectFlow::load_syntax (syntax, alist);

    Librarian::add_type (Select::component, "flow_right", alist, syntax, &make);
  }
} Select_flow_right_syntax;

struct SelectFlowFront : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_front)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_y (outside) < geo.cell_y (inside);
  }

  // Create and Destroy.
  SelectFlowFront (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowFrontSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowFront (al); }

  SelectFlowFrontSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from front of specified volume.");
    SelectFlow::load_syntax (syntax, alist);

    Librarian::add_type (Select::component, "flow_front", alist, syntax, &make);
  }
} Select_flow_front_syntax;

struct SelectFlowBack : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_back)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_y (outside) < geo.cell_y (inside);
  }

  // Create and Destroy.
  SelectFlowBack (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowBackSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowBack (al); }

  SelectFlowBackSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from back of specified volume.");
    SelectFlow::load_syntax (syntax, alist);

    Librarian::add_type (Select::component, "flow_back", alist, syntax, &make);
  }
} Select_flow_back_syntax;

// select_flow.C ends here.
<commit_msg>kvl-t<commit_after>// select_flow.C --- Flows in and out of a volume.
//
// Copyright 2006 KVL and Per Abrahamsen
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#define BUILD_DLL
#include "select_value.h"
#include "block.h"
#include "alist.h"
#include "volume.h"
#include "border.h"
#include "geometry.h"
#include "treelog.h"
#include "librarian.h"
#ifdef DEBUG_EDGES
#include <sstream>
#endif

class SelectFlow : public SelectValue
{
  // Content.
private:

  const bool density;
  std::auto_ptr<Volume> volume;
  const Geometry* last_geo;
  std::vector<size_t> edges;
  std::vector<double> weight;

  // Use.
protected:
  virtual bool use_edge (const Geometry&, int out, int in) const = 0;

  // Output routines.
private:
  void output_array (const std::vector<double>&,
                     const Geometry*, const Soil*, const Vegetation*, Treelog&);

  // Create and Destroy.
private:
  symbol default_dimension (const symbol spec_dim) const;
  bool initialize (const Volume& volume,
		   const std::string& timestep, Treelog& msg);
  bool check_border (const Border& border,
                     const Volume& default_volume,
                     Treelog& msg) const;
public:
  static void load_syntax (Syntax& syntax, AttributeList& alist);
  SelectFlow (Block&);
};

void
SelectFlow::load_syntax (Syntax& syntax, AttributeList& alist)
{
  SelectValue::load_syntax (syntax, alist);
  syntax.add ("density", Syntax::Boolean, Syntax::Const,
              "If true, divide value with volume height.");
  alist.add ("density", false);
  syntax.add_object ("volume", Volume::component,
                     Syntax::Const, Syntax::Singleton,
                     "Soil volume to log flow into.");
  alist.add ("volume", Volume::infinite_box ());
}

symbol
SelectFlow::default_dimension (const symbol spec_dim) const
{
  if (density)
    return spec_dim;

  return Units::multiply (spec_dim, Units::cm2 ());
}

bool
SelectFlow::initialize (const Volume& default_volume,
                        const std::string& timestep, Treelog& msg)
{
  bool ok = true;

  if (!Select::initialize (default_volume, timestep, msg))
    ok = false;

  if (!volume->limit (default_volume, msg))
    ok = false;

  return ok;
}

bool
SelectFlow::check_border (const Border& border, const Volume& default_volume,
                          Treelog& msg) const
{ return volume->check_border (border, default_volume, msg); }

void
SelectFlow::output_array (const std::vector<double>& array,
                          const Geometry* geo, const Soil*, const Vegetation*,
			  Treelog& msg)
{
  if (geo != last_geo)
    {
      Treelog::Open nest (msg, name);
      last_geo = geo;
      const size_t size = geo->edge_size ();
      edges.clear ();
      weight.clear ();
      double total_area = 0.0;
      for (size_t e = 0; e < size; e++)
        {
          const int from = geo->edge_from (e);
          const bool from_inside = geo->cell_center_in_volume (from, *volume);
          const int to = geo->edge_to (e);
          const bool to_inside = geo->cell_center_in_volume (to, *volume);
          if (from_inside)
            {
              if (to_inside)
                // Both inside volume, don't use.
                continue;
              if (!use_edge (*geo, to, from))
                continue;
            }
          else
            {
              if (!to_inside)
                // Both outside volume, don't use.
                continue;
              if (!use_edge (*geo, from, to))
                continue;
            }
          edges.push_back (e);
          double area = geo->edge_area (e);
          total_area += area;
          if (from_inside)
            // Positive inwards.
            area *= -1;
          weight.push_back (area);
        }
      if (weight.size () ==0)
        msg.warning ("No edges found");
      else
        daisy_assert (std::isnormal (total_area));

      if (density)
        for (size_t i = 0; i < weight.size (); i++)
          weight[i] /= total_area;
#ifdef DEBUG_EDGES
      std::ostringstream tmp;
      tmp << "Total area: " << total_area << ", density = " << density
          << ", #edges = " << edges.size ();
      for (size_t i = 0; i < edges.size (); i++)
        tmp << "\n" << geo->edge_name (edges[i]) << ": weigth " << weight[i];
      msg.message (tmp.str ());
#endif
      daisy_assert (edges.size () == weight.size ());
    }
  daisy_assert (edges.size () <= array.size ());

  double sum = 0.0;
  for (size_t i = 0; i < edges.size (); i++)
    sum += array[edges[i]] * weight[i];

  add_result (sum);
}

SelectFlow::SelectFlow (Block& al)
  : SelectValue (al),
    density (al.flag ("density")),
    volume (Volume::build_obsolete (al)),
    last_geo (NULL)
{ }

struct SelectFlowTop : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_above)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_z (outside) > geo.cell_z (inside);
  }

  // Create and Destroy.
  SelectFlowTop (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowTopSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowTop (al); }

  SelectFlowTopSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from top of specified volume.");
    SelectFlow::load_syntax (syntax, alist);
    syntax.add ("from", "cm", Syntax::OptionalConst,
		"Specify height (negative) to measure from.\n\
By default, measure from the top.\n\
OBSOLETE: Use (volume box (top FROM)) instead.");

    Librarian::add_type (Select::component, "flow_top", alist, syntax, &make);
  }
} Select_flow_top_syntax;

static struct SelectFluxTopSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowTop (al); }

  SelectFluxTopSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Flux leaving top of specified volume.\n\
OBSOLETE: Use '(flow_top (negate true) (density true))' instead.");
    SelectFlow::load_syntax (syntax, alist);
    syntax.add ("from", "cm", Syntax::OptionalConst,
		"Specify height (negative) to measure from.\n\
By default, measure from the top.\n\
OBSOLETE: Use (volume box (top FROM)) instead.");
    alist.add ("density", true);
    Librarian::add_type (Select::component, "flux_top", alist, syntax, &make);
  }
} Select_flux_top_syntax;

struct SelectFlowBottom : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_below)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_z (outside) < geo.cell_z (inside);
  }

  // Create and Destroy.
  SelectFlowBottom (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowBottomSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowBottom (al); }

  SelectFlowBottomSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from bottom of specified volume.");
    SelectFlow::load_syntax (syntax, alist);
    syntax.add ("to", "cm", Syntax::OptionalConst,
		"Specify height (negative) to measure interval.\n\
By default, measure to the bottom.\n\
OBSOLETE: Use (volume box (bottom TO)) instead.");

    Librarian::add_type (Select::component, "flow_bottom", alist, syntax, &make);
  }
} Select_flow_bottom_syntax;

static struct SelectFluxBottomSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowBottom (al); }

  SelectFluxBottomSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Flux entering bottom of specified volume.\n\
OBSOLETE: Use '(flow_bottom (density true))' instead.");
    SelectFlow::load_syntax (syntax, alist);
    syntax.add ("to", "cm", Syntax::OptionalConst,
		"Specify height (negative) to measure to.\n\
By default, measure from the bottom.\n\
OBSOLETE: Use (volume box (bottom TO)) instead.");
    alist.add ("density", true);
    Librarian::add_type (Select::component, "flux_bottom", alist, syntax, &make);
  }
} Select_flux_bottom_syntax;

struct SelectFlowLeft : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_left)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_x (outside) < geo.cell_x (inside);
  }

  // Create and Destroy.
  SelectFlowLeft (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowLeftSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowLeft (al); }

  SelectFlowLeftSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from left of specified volume.");
    SelectFlow::load_syntax (syntax, alist);

    Librarian::add_type (Select::component, "flow_left", alist, syntax, &make);
  }
} Select_flow_left_syntax;

struct SelectFlowRight : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_right)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_x (outside) > geo.cell_x (inside);
  }

  // Create and Destroy.
  SelectFlowRight (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowRightSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowRight (al); }

  SelectFlowRightSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from right of specified volume.");
    SelectFlow::load_syntax (syntax, alist);

    Librarian::add_type (Select::component, "flow_right", alist, syntax, &make);
  }
} Select_flow_right_syntax;

struct SelectFlowFront : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_front)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_y (outside) < geo.cell_y (inside);
  }

  // Create and Destroy.
  SelectFlowFront (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowFrontSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowFront (al); }

  SelectFlowFrontSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from front of specified volume.");
    SelectFlow::load_syntax (syntax, alist);

    Librarian::add_type (Select::component, "flow_front", alist, syntax, &make);
  }
} Select_flow_front_syntax;

struct SelectFlowBack : public SelectFlow
{
  bool use_edge (const Geometry& geo, int outside, int inside) const
  {
    if (outside == Geometry::cell_back)
      return true;
    if (!geo.cell_is_internal (outside))
      return false;
    daisy_assert (geo.cell_is_internal (inside));
    return geo.cell_y (outside) < geo.cell_y (inside);
  }

  // Create and Destroy.
  SelectFlowBack (Block& al)
    : SelectFlow (al)
  { }
};

static struct SelectFlowBackSyntax
{
  static Model& make (Block& al)
  { return *new SelectFlowBack (al); }

  SelectFlowBackSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "Extract flow from back of specified volume.");
    SelectFlow::load_syntax (syntax, alist);

    Librarian::add_type (Select::component, "flow_back", alist, syntax, &make);
  }
} Select_flow_back_syntax;

// select_flow.C ends here.
<|endoftext|>


<commit_before>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2008 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * 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 Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

# include <cppunit/extensions/TestFactoryRegistry.h>
# include <cppunit/extensions/HelperMacros.h>

#include "base/fscapi.h"
#include "base/util/utils.h"
#include "base/util/StringBuffer.h"
#include "spds/SyncManagerConfig.h"
#include "client/FileSyncItem.h"
#include "inputStream/FileDataInputStream.h"

#include "common/inputStream/InputStreamTest.h"
#include "testUtils.h"

#define TEST_FILE_NAME      "test_LICENSE_unix.txt"      // a txt file with unix newlines

USE_NAMESPACE

class FileSyncItemTest : public CppUnit::TestFixture {

    CPPUNIT_TEST_SUITE(FileSyncItemTest);
    CPPUNIT_TEST(testFileSyncItemRawInputStream);
    CPPUNIT_TEST(testFileSyncItemFileDataInputStream);
    CPPUNIT_TEST_SUITE_END();

public:

    void setUp() {}
    void tearDown() {}

private:

    /**
     * 1. Creates a FileSyncItem with a FileInputStream/FileDataInputStream
     *    and reads the stream from there
     * 2. Clones the FileSyncItem, then reads again the stream
     * Use the inputStream tests defined in InputStreamTest class.
     */
    void testFileSyncItemInputStream(const bool isFileData) {

        StringBuffer fileName = getTestFileFullPath("FileInputStreamTest", TEST_FILE_NAME);

        FileSyncItem item(fileName, isFileData);
        InputStreamTest test;

        // raw data
        char* fileContent = loadTestFile("FileInputStreamTest", TEST_FILE_NAME, true);  // must be binary mode!
        int fileSize = (int)fgetsize(fileName.c_str());

        // file data object
        if (isFileData) {
            FileData fileData;
            fileData.setName(TEXT(TEST_FILE_NAME));
            fileData.setSize(fileSize);
            fileData.setBody(fileContent, fileSize);

            // re-set the expected results
            delete [] fileContent;
            fileContent = fileData.format();
            fileSize = (int)strlen(fileContent);
        }

        InputStream* stream = item.getInputStream();
        CPPUNIT_ASSERT (stream);
        CPPUNIT_ASSERT (item.getDataSize() == fileSize);

        if (stream) {
            test.testReadManyChunks(*stream, fileContent, fileSize, 1024);
        }

        // Clone the item
        FileSyncItem* itemCloned = (FileSyncItem*)item.clone();
        stream = itemCloned->getInputStream();
        CPPUNIT_ASSERT (stream);
        CPPUNIT_ASSERT (item.getDataSize() == fileSize);

        if (stream) {
            test.testReadManyChunks(*stream, fileContent, fileSize, 899);
        }

        delete itemCloned;
        delete [] fileContent;
    }

    /// Tests the raw file data read() from the FileSyncItem
    void testFileSyncItemRawInputStream() {
        testFileSyncItemInputStream(false);
    }

    /// Tests the file object data read() from the FileSyncItem
    void testFileSyncItemFileDataInputStream() {
        testFileSyncItemInputStream(true);
    }

};

CPPUNIT_TEST_SUITE_REGISTRATION( FileSyncItemTest );
<commit_msg>fixed fileSyncItem test on FileDataInputStream ("modified" attribute has been added)<commit_after>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2008 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * 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 Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

# include <cppunit/extensions/TestFactoryRegistry.h>
# include <cppunit/extensions/HelperMacros.h>

#include "base/fscapi.h"
#include "base/util/utils.h"
#include "base/util/StringBuffer.h"
#include "spds/SyncManagerConfig.h"
#include "client/FileSyncItem.h"
#include "inputStream/FileDataInputStream.h"

#include "common/inputStream/InputStreamTest.h"
#include "testUtils.h"

#define TEST_FILE_NAME      "test_LICENSE_unix.txt"      // a txt file with unix newlines

USE_NAMESPACE

class FileSyncItemTest : public CppUnit::TestFixture {

    CPPUNIT_TEST_SUITE(FileSyncItemTest);
    CPPUNIT_TEST(testFileSyncItemRawInputStream);
    CPPUNIT_TEST(testFileSyncItemFileDataInputStream);
    CPPUNIT_TEST_SUITE_END();

public:

    void setUp() {}
    void tearDown() {}

private:

    /**
     * 1. Creates a FileSyncItem with a FileInputStream/FileDataInputStream
     *    and reads the stream from there
     * 2. Clones the FileSyncItem, then reads again the stream
     * Use the inputStream tests defined in InputStreamTest class.
     */
    void testFileSyncItemInputStream(const bool isFileData) {

        StringBuffer fileName = getTestFileFullPath("FileInputStreamTest", TEST_FILE_NAME);

        FileSyncItem item(fileName, isFileData);
        InputStreamTest test;

        // raw data
        char* fileContent = loadTestFile("FileInputStreamTest", TEST_FILE_NAME, true);  // must be binary mode!
        int fileSize = (int)fgetsize(fileName.c_str());

        // file data object
        if (isFileData) {
            FileData fileData;
            fileData.setName(TEXT(TEST_FILE_NAME));
            fileData.setSize(fileSize);
            fileData.setBody(fileContent, fileSize);

            unsigned long tstamp = getFileModTime(fileName);
            StringBuffer modTime = unixTimeToString(tstamp, true);  // file's mod time is already in UTC
            WString wmodTime;
            wmodTime = modTime;
            fileData.setModified(wmodTime);

            // re-set the expected results
            delete [] fileContent;
            fileContent = fileData.format();
            fileSize = (int)strlen(fileContent);
        }

        InputStream* stream = item.getInputStream();
        CPPUNIT_ASSERT (stream);
        CPPUNIT_ASSERT (item.getDataSize() == fileSize);

        if (stream) {
            test.testReadManyChunks(*stream, fileContent, fileSize, 1024);
        }

        // Clone the item
        FileSyncItem* itemCloned = (FileSyncItem*)item.clone();
        stream = itemCloned->getInputStream();
        CPPUNIT_ASSERT (stream);
        CPPUNIT_ASSERT (item.getDataSize() == fileSize);

        if (stream) {
            test.testReadManyChunks(*stream, fileContent, fileSize, 899);
        }

        delete itemCloned;
        delete [] fileContent;
    }

    /// Tests the raw file data read() from the FileSyncItem
    void testFileSyncItemRawInputStream() {
        testFileSyncItemInputStream(false);
    }

    /// Tests the file object data read() from the FileSyncItem
    void testFileSyncItemFileDataInputStream() {
        testFileSyncItemInputStream(true);
    }

};

CPPUNIT_TEST_SUITE_REGISTRATION( FileSyncItemTest );
<|endoftext|>


<commit_before>#define MS_CLASS "RTC::PlainRtpTransport"
// #define MS_LOG_DEV

#include "RTC/PlainRtpTransport.hpp"
#include "DepLibUV.hpp"
#include "Logger.hpp"
#include "MediaSoupError.hpp"
#include "Settings.hpp"
#include "Utils.hpp"
#include "RTC/Consumer.hpp"
#include "RTC/Producer.hpp"

namespace RTC
{
	/* Instance methods. */

	PlainRtpTransport::PlainRtpTransport(
	  RTC::Transport::Listener* listener,
	  Channel::Notifier* notifier,
	  uint32_t transportId,
	  Options& options)
	  : RTC::Transport::Transport(listener, notifier, transportId)
	{
		MS_TRACE();

		int err;

		switch (Utils::IP::GetFamily(options.remoteIP))
		{
			case AF_INET:
			{
				if (!Settings::configuration.hasIPv4)
					MS_THROW_ERROR("IPv4 disabled");

				err = uv_ip4_addr(
				  options.remoteIP.c_str(),
				  static_cast<int>(options.remotePort),
				  reinterpret_cast<struct sockaddr_in*>(&this->remoteAddrStorage));
				if (err != 0)
					MS_ABORT("uv_ipv4_addr() failed: %s", uv_strerror(err));

				this->udpSocket = new RTC::UdpSocket(this, AF_INET);

				break;
			}

			case AF_INET6:
			{
				if (!Settings::configuration.hasIPv6)
					MS_THROW_ERROR("IPv6 disabled");

				err = uv_ip6_addr(
				  options.remoteIP.c_str(),
				  static_cast<int>(options.remotePort),
				  reinterpret_cast<struct sockaddr_in6*>(&this->remoteAddrStorage));
				if (err != 0)
					MS_ABORT("uv_ipv6_addr() failed: %s", uv_strerror(err));

				this->udpSocket = new RTC::UdpSocket(this, AF_INET6);

				break;
			}

			default:
			{
				MS_THROW_ERROR("invalid destination IP '%s'", options.remoteIP.c_str());

				break;
			}
		}

		this->tuple = new RTC::TransportTuple(
		  this->udpSocket, reinterpret_cast<struct sockaddr*>(&this->remoteAddrStorage));
	}

	PlainRtpTransport::~PlainRtpTransport()
	{
		MS_TRACE();

		delete this->tuple;

		if (this->udpSocket != nullptr)
			this->udpSocket->Destroy();
	}

	Json::Value PlainRtpTransport::ToJson() const
	{
		MS_TRACE();

		static const Json::StaticString JsonStringTransportId{ "transportId" };
		static const Json::StaticString JsonStringTuple{ "tuple" };
		static const Json::StaticString JsonStringRtpListener{ "rtpListener" };

		Json::Value json(Json::objectValue);

		// Add transportId.
		json[JsonStringTransportId] = Json::UInt{ this->transportId };

		// Add tuple.
		if (this->tuple != nullptr)
			json[JsonStringTuple] = this->tuple->ToJson();

		// Add rtpListener.
		json[JsonStringRtpListener] = this->rtpListener.ToJson();

		return json;
	}

	Json::Value PlainRtpTransport::GetStats() const
	{
		MS_TRACE();

		Json::Value json(Json::objectValue);

		return json;
	}

	void PlainRtpTransport::SendRtpPacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		if (!IsConnected())
			return;

		const uint8_t* data = packet->GetData();
		size_t len          = packet->GetSize();

		// Mirror RTP if needed.
		if (this->mirrorTuple != nullptr && this->mirroringOptions.sendRtp)
			this->mirrorTuple->Send(data, len);

		this->tuple->Send(data, len);
	}

	void PlainRtpTransport::SendRtcpPacket(RTC::RTCP::Packet* packet)
	{
		MS_TRACE();

		if (!IsConnected())
			return;

		const uint8_t* data = packet->GetData();
		size_t len          = packet->GetSize();

		// Mirror RTCP if needed.
		if (this->mirrorTuple != nullptr && this->mirroringOptions.sendRtcp)
			this->mirrorTuple->Send(data, len);

		this->tuple->Send(data, len);
	}

	bool PlainRtpTransport::IsConnected() const
	{
		return true;
	}

	void PlainRtpTransport::SendRtcpCompoundPacket(RTC::RTCP::CompoundPacket* packet)
	{
		MS_TRACE();

		if (!IsConnected())
			return;

		const uint8_t* data = packet->GetData();
		size_t len          = packet->GetSize();

		// Mirror RTCP if needed.
		if (this->mirrorTuple != nullptr && this->mirroringOptions.sendRtcp)
			this->mirrorTuple->Send(data, len);

		this->tuple->Send(data, len);
	}

	inline void PlainRtpTransport::OnPacketRecv(RTC::TransportTuple* tuple, const uint8_t* data, size_t len)
	{
		MS_TRACE();

		// Check if it's RTCP.
		if (RTCP::Packet::IsRtcp(data, len))
		{
			OnRtcpDataRecv(tuple, data, len);
		}
		// Check if it's RTP.
		else if (RtpPacket::IsRtp(data, len))
		{
			OnRtpDataRecv(tuple, data, len);
		}
		else
		{
			MS_WARN_DEV("ignoring received packet of unknown type");
		}
	}

	inline void PlainRtpTransport::OnRtpDataRecv(
	  RTC::TransportTuple* /*tuple*/, const uint8_t* data, size_t len)
	{
		MS_TRACE();

		// Mirror RTP if needed.
		if (this->mirrorTuple != nullptr && this->mirroringOptions.recvRtp)
			this->mirrorTuple->Send(data, len);

		RTC::RtpPacket* packet = RTC::RtpPacket::Parse(data, len);

		if (packet == nullptr)
		{
			MS_WARN_TAG(rtp, "received data is not a valid RTP packet");

			return;
		}

		// Apply the Transport RTP header extension ids so the RTP listener can use them.

		if (this->headerExtensionIds.rid != 0u)
		{
			packet->AddExtensionMapping(
			  RtpHeaderExtensionUri::Type::RTP_STREAM_ID, this->headerExtensionIds.rid);
		}
		if (this->headerExtensionIds.absSendTime != 0u)
		{
			packet->AddExtensionMapping(
			  RtpHeaderExtensionUri::Type::ABS_SEND_TIME, this->headerExtensionIds.absSendTime);
		}

		// Get the associated Producer.
		RTC::Producer* producer = this->rtpListener.GetProducer(packet);

		if (producer == nullptr)
		{
			MS_WARN_TAG(
			  rtp,
			  "no suitable Producer for received RTP packet [ssrc:%" PRIu32 ", payloadType:%" PRIu8 "]",
			  packet->GetSsrc(),
			  packet->GetPayloadType());

			delete packet;
			return;
		}

		MS_DEBUG_DEV(
		  "RTP packet received [ssrc:%" PRIu32 ", payloadType:%" PRIu8 ", producer:%" PRIu32 "]",
		  packet->GetSsrc(),
		  packet->GetPayloadType(),
		  producer->producerId);

		// Pass the RTP packet to the corresponding Producer.
		producer->ReceiveRtpPacket(packet);

		delete packet;
	}

	inline void PlainRtpTransport::OnRtcpDataRecv(
	  RTC::TransportTuple* /*tuple*/, const uint8_t* data, size_t len)
	{
		MS_TRACE();

		// Mirror RTCP if needed.
		if (this->mirrorTuple != nullptr && this->mirroringOptions.recvRtcp)
			this->mirrorTuple->Send(data, len);

		RTC::RTCP::Packet* packet = RTC::RTCP::Packet::Parse(data, len);

		if (packet == nullptr)
		{
			MS_WARN_TAG(rtcp, "received data is not a valid RTCP compound or single packet");

			return;
		}

		// Handle each RTCP packet.
		while (packet != nullptr)
		{
			HandleRtcpPacket(packet);

			RTC::RTCP::Packet* previousPacket = packet;

			packet = packet->GetNext();
			delete previousPacket;
		}
	}

	void PlainRtpTransport::OnPacketRecv(
	  RTC::UdpSocket* socket, const uint8_t* data, size_t len, const struct sockaddr* remoteAddr)
	{
		MS_TRACE();

		RTC::TransportTuple tuple(socket, remoteAddr);

		OnPacketRecv(&tuple, data, len);
	}
} // namespace RTC
<commit_msg>Also send RTCP in PlainRtpTransport (shoulf fix #197)<commit_after>#define MS_CLASS "RTC::PlainRtpTransport"
// #define MS_LOG_DEV

#include "RTC/PlainRtpTransport.hpp"
#include "DepLibUV.hpp"
#include "Logger.hpp"
#include "MediaSoupError.hpp"
#include "Settings.hpp"
#include "Utils.hpp"
#include "RTC/Consumer.hpp"
#include "RTC/Producer.hpp"

namespace RTC
{
	/* Instance methods. */

	PlainRtpTransport::PlainRtpTransport(
	  RTC::Transport::Listener* listener,
	  Channel::Notifier* notifier,
	  uint32_t transportId,
	  Options& options)
	  : RTC::Transport::Transport(listener, notifier, transportId)
	{
		MS_TRACE();

		int err;

		switch (Utils::IP::GetFamily(options.remoteIP))
		{
			case AF_INET:
			{
				if (!Settings::configuration.hasIPv4)
					MS_THROW_ERROR("IPv4 disabled");

				err = uv_ip4_addr(
				  options.remoteIP.c_str(),
				  static_cast<int>(options.remotePort),
				  reinterpret_cast<struct sockaddr_in*>(&this->remoteAddrStorage));
				if (err != 0)
					MS_ABORT("uv_ipv4_addr() failed: %s", uv_strerror(err));

				this->udpSocket = new RTC::UdpSocket(this, AF_INET);

				break;
			}

			case AF_INET6:
			{
				if (!Settings::configuration.hasIPv6)
					MS_THROW_ERROR("IPv6 disabled");

				err = uv_ip6_addr(
				  options.remoteIP.c_str(),
				  static_cast<int>(options.remotePort),
				  reinterpret_cast<struct sockaddr_in6*>(&this->remoteAddrStorage));
				if (err != 0)
					MS_ABORT("uv_ipv6_addr() failed: %s", uv_strerror(err));

				this->udpSocket = new RTC::UdpSocket(this, AF_INET6);

				break;
			}

			default:
			{
				MS_THROW_ERROR("invalid destination IP '%s'", options.remoteIP.c_str());

				break;
			}
		}

		// Create a single tuple.
		this->tuple = new RTC::TransportTuple(
		  this->udpSocket, reinterpret_cast<struct sockaddr*>(&this->remoteAddrStorage));

		// Start the RTCP timer.
		this->rtcpTimer->Start(static_cast<uint64_t>(RTC::RTCP::MaxVideoIntervalMs / 2));
	}

	PlainRtpTransport::~PlainRtpTransport()
	{
		MS_TRACE();

		delete this->tuple;

		if (this->udpSocket != nullptr)
			this->udpSocket->Destroy();
	}

	Json::Value PlainRtpTransport::ToJson() const
	{
		MS_TRACE();

		static const Json::StaticString JsonStringTransportId{ "transportId" };
		static const Json::StaticString JsonStringTuple{ "tuple" };
		static const Json::StaticString JsonStringRtpListener{ "rtpListener" };

		Json::Value json(Json::objectValue);

		// Add transportId.
		json[JsonStringTransportId] = Json::UInt{ this->transportId };

		// Add tuple.
		if (this->tuple != nullptr)
			json[JsonStringTuple] = this->tuple->ToJson();

		// Add rtpListener.
		json[JsonStringRtpListener] = this->rtpListener.ToJson();

		return json;
	}

	Json::Value PlainRtpTransport::GetStats() const
	{
		MS_TRACE();

		Json::Value json(Json::objectValue);

		return json;
	}

	void PlainRtpTransport::SendRtpPacket(RTC::RtpPacket* packet)
	{
		MS_TRACE();

		if (!IsConnected())
			return;

		const uint8_t* data = packet->GetData();
		size_t len          = packet->GetSize();

		// Mirror RTP if needed.
		if (this->mirrorTuple != nullptr && this->mirroringOptions.sendRtp)
			this->mirrorTuple->Send(data, len);

		this->tuple->Send(data, len);
	}

	void PlainRtpTransport::SendRtcpPacket(RTC::RTCP::Packet* packet)
	{
		MS_TRACE();

		if (!IsConnected())
			return;

		const uint8_t* data = packet->GetData();
		size_t len          = packet->GetSize();

		// Mirror RTCP if needed.
		if (this->mirrorTuple != nullptr && this->mirroringOptions.sendRtcp)
			this->mirrorTuple->Send(data, len);

		this->tuple->Send(data, len);
	}

	bool PlainRtpTransport::IsConnected() const
	{
		return true;
	}

	void PlainRtpTransport::SendRtcpCompoundPacket(RTC::RTCP::CompoundPacket* packet)
	{
		MS_TRACE();

		if (!IsConnected())
			return;

		const uint8_t* data = packet->GetData();
		size_t len          = packet->GetSize();

		// Mirror RTCP if needed.
		if (this->mirrorTuple != nullptr && this->mirroringOptions.sendRtcp)
			this->mirrorTuple->Send(data, len);

		this->tuple->Send(data, len);
	}

	inline void PlainRtpTransport::OnPacketRecv(RTC::TransportTuple* tuple, const uint8_t* data, size_t len)
	{
		MS_TRACE();

		// Check if it's RTCP.
		if (RTCP::Packet::IsRtcp(data, len))
		{
			OnRtcpDataRecv(tuple, data, len);
		}
		// Check if it's RTP.
		else if (RtpPacket::IsRtp(data, len))
		{
			OnRtpDataRecv(tuple, data, len);
		}
		else
		{
			MS_WARN_DEV("ignoring received packet of unknown type");
		}
	}

	inline void PlainRtpTransport::OnRtpDataRecv(
	  RTC::TransportTuple* /*tuple*/, const uint8_t* data, size_t len)
	{
		MS_TRACE();

		// Mirror RTP if needed.
		if (this->mirrorTuple != nullptr && this->mirroringOptions.recvRtp)
			this->mirrorTuple->Send(data, len);

		RTC::RtpPacket* packet = RTC::RtpPacket::Parse(data, len);

		if (packet == nullptr)
		{
			MS_WARN_TAG(rtp, "received data is not a valid RTP packet");

			return;
		}

		// Apply the Transport RTP header extension ids so the RTP listener can use them.

		if (this->headerExtensionIds.rid != 0u)
		{
			packet->AddExtensionMapping(
			  RtpHeaderExtensionUri::Type::RTP_STREAM_ID, this->headerExtensionIds.rid);
		}
		if (this->headerExtensionIds.absSendTime != 0u)
		{
			packet->AddExtensionMapping(
			  RtpHeaderExtensionUri::Type::ABS_SEND_TIME, this->headerExtensionIds.absSendTime);
		}

		// Get the associated Producer.
		RTC::Producer* producer = this->rtpListener.GetProducer(packet);

		if (producer == nullptr)
		{
			MS_WARN_TAG(
			  rtp,
			  "no suitable Producer for received RTP packet [ssrc:%" PRIu32 ", payloadType:%" PRIu8 "]",
			  packet->GetSsrc(),
			  packet->GetPayloadType());

			delete packet;
			return;
		}

		MS_DEBUG_DEV(
		  "RTP packet received [ssrc:%" PRIu32 ", payloadType:%" PRIu8 ", producer:%" PRIu32 "]",
		  packet->GetSsrc(),
		  packet->GetPayloadType(),
		  producer->producerId);

		// Pass the RTP packet to the corresponding Producer.
		producer->ReceiveRtpPacket(packet);

		delete packet;
	}

	inline void PlainRtpTransport::OnRtcpDataRecv(
	  RTC::TransportTuple* /*tuple*/, const uint8_t* data, size_t len)
	{
		MS_TRACE();

		// Mirror RTCP if needed.
		if (this->mirrorTuple != nullptr && this->mirroringOptions.recvRtcp)
			this->mirrorTuple->Send(data, len);

		RTC::RTCP::Packet* packet = RTC::RTCP::Packet::Parse(data, len);

		if (packet == nullptr)
		{
			MS_WARN_TAG(rtcp, "received data is not a valid RTCP compound or single packet");

			return;
		}

		// Handle each RTCP packet.
		while (packet != nullptr)
		{
			HandleRtcpPacket(packet);

			RTC::RTCP::Packet* previousPacket = packet;

			packet = packet->GetNext();
			delete previousPacket;
		}
	}

	void PlainRtpTransport::OnPacketRecv(
	  RTC::UdpSocket* socket, const uint8_t* data, size_t len, const struct sockaddr* remoteAddr)
	{
		MS_TRACE();

		RTC::TransportTuple tuple(socket, remoteAddr);

		OnPacketRecv(&tuple, data, len);
	}
} // namespace RTC
<|endoftext|>


<commit_before>#include <iostream>
#include <oclutil/oclutil.hpp>
using namespace clu;

int main() {
    std::cout << "OpenCL devices:" << std::endl << std::endl;
    auto dev = device_list();
    for (auto d = dev.begin(); d != dev.end(); d++) {
	std::cout << "  " << d->getInfo<CL_DEVICE_NAME>() << std::endl
		  << "    CL_DEVICE_OPENCL_C_VERSION    = " << d->getInfo<CL_DEVICE_OPENCL_C_VERSION>() << std::endl
		  << "    CL_DEVICE_MAX_COMPUTE_UNITS   = " << d->getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>() << std::endl
	          << "    CL_DEVICE_HOST_UNIFIED_MEMORY = " << d->getInfo<CL_DEVICE_HOST_UNIFIED_MEMORY>() << std::endl
		  << "    CL_DEVICE_GLOBAL_MEM_SIZE     = " << d->getInfo<CL_DEVICE_GLOBAL_MEM_SIZE>() << std::endl
		  << "    CL_DEVICE_LOCAL_MEM_SIZE      = " << d->getInfo<CL_DEVICE_LOCAL_MEM_SIZE>() << std::endl
		  << "    CL_DEVICE_MAX_CLOCK_FREQUENCY = " << d->getInfo<CL_DEVICE_MAX_CLOCK_FREQUENCY>() << std::endl
		  << std::endl;
    }
}
<commit_msg>Show platform in device list<commit_after>#include <iostream>
#include <oclutil/oclutil.hpp>
using namespace clu;

int main() {
    std::cout << "OpenCL devices:" << std::endl << std::endl;
    auto dev = device_list();
    for (auto d = dev.begin(); d != dev.end(); d++) {
	std::cout << "  " << d->getInfo<CL_DEVICE_NAME>() << std::endl
		  << "    CL_PLATFORM_NAME              = " << cl::Platform(d->getInfo<CL_DEVICE_PLATFORM>()).getInfo<CL_PLATFORM_NAME>() << std::endl
		  << "    CL_DEVICE_OPENCL_C_VERSION    = " << d->getInfo<CL_DEVICE_OPENCL_C_VERSION>() << std::endl
		  << "    CL_DEVICE_MAX_COMPUTE_UNITS   = " << d->getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>() << std::endl
	          << "    CL_DEVICE_HOST_UNIFIED_MEMORY = " << d->getInfo<CL_DEVICE_HOST_UNIFIED_MEMORY>() << std::endl
		  << "    CL_DEVICE_GLOBAL_MEM_SIZE     = " << d->getInfo<CL_DEVICE_GLOBAL_MEM_SIZE>() << std::endl
		  << "    CL_DEVICE_LOCAL_MEM_SIZE      = " << d->getInfo<CL_DEVICE_LOCAL_MEM_SIZE>() << std::endl
		  << "    CL_DEVICE_MAX_CLOCK_FREQUENCY = " << d->getInfo<CL_DEVICE_MAX_CLOCK_FREQUENCY>() << std::endl
		  << std::endl;
    }
}
<|endoftext|>


<commit_before>//  (C) Copyright Gennadiy Rozental 2001-2006.
//  (C) Copyright Beman Dawes 2001.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision$
//
//  Description : tests an ability of Program Execution Monitor to catch
//  system exceptions. Should fail during run.
// ***************************************************************************

#ifdef __MWERKS__
//  Metrowerks doesn't build knowledge of what runtime libraries to link with
//  into their compiler. Instead they depend on pragmas in their standard
//  library headers. That creates the odd situation that certain programs
//  won't link unless at least one standard header is included. Note that
//  this problem is highly dependent on enviroment variables and command
//  line options, so just because the problem doesn't show up on one
//  system doesn't mean it has been fixed. Remove this workaround only
//  when told by Metrowerks that it is safe to do so.
#include <cstddef> //Metrowerks linker needs at least one standard library
#endif

int cpp_main( int, char *[] )  // note the name
{
    int div = 0;
    return 10 / div;
}

//____________________________________________________________________________//

// ***************************************************************************
//  Revision History :
//
//  $Log$
//  Revision 1.15  2006/03/19 11:49:04  rogeeff
//  *** empty log message ***
//
//  Revision 1.14  2005/05/11 05:07:57  rogeeff
//  licence update
//
//  Revision 1.13  2005/05/21 06:26:10  rogeeff
//  licence update
//
//  Revision 1.12  2005/01/07 22:06:44  beman_dawes
//  Fix Metrowerks link failures for some compiler configurations. See comment in code. (fix from Ed Swartz of Metrowerks)
//
//  Revision 1.11  2003/12/01 00:42:38  rogeeff
//  prerelease cleaning
//

// ***************************************************************************

// EOF
<commit_msg>Patch from Trac #583.<commit_after>//  (C) Copyright Gennadiy Rozental 2001-2006.
//  (C) Copyright Beman Dawes 2001.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision$
//
//  Description : tests an ability of Program Execution Monitor to catch
//  system exceptions. Should fail during run.
// ***************************************************************************

#ifdef __MWERKS__
//  Metrowerks doesn't build knowledge of what runtime libraries to link with
//  into their compiler. Instead they depend on pragmas in their standard
//  library headers. That creates the odd situation that certain programs
//  won't link unless at least one standard header is included. Note that
//  this problem is highly dependent on enviroment variables and command
//  line options, so just because the problem doesn't show up on one
//  system doesn't mean it has been fixed. Remove this workaround only
//  when told by Metrowerks that it is safe to do so.
#include <cstddef> //Metrowerks linker needs at least one standard library
#endif

#if defined(__IBMCPP__)
#pragma options check=divzero
#endif

int cpp_main( int, char *[] )  // note the name
{
    int div = 0;
    return 10 / div;
}

//____________________________________________________________________________//

// ***************************************************************************
//  Revision History :
//
//  $Log$
//  Revision 1.15.2.1  2007/06/01 16:41:06  witt
//  Patch from Trac #583.
//
//  Revision 1.15  2006/03/19 11:49:04  rogeeff
//  *** empty log message ***
//
//  Revision 1.14  2005/05/11 05:07:57  rogeeff
//  licence update
//
//  Revision 1.13  2005/05/21 06:26:10  rogeeff
//  licence update
//
//  Revision 1.12  2005/01/07 22:06:44  beman_dawes
//  Fix Metrowerks link failures for some compiler configurations. See comment in code. (fix from Ed Swartz of Metrowerks)
//
//  Revision 1.11  2003/12/01 00:42:38  rogeeff
//  prerelease cleaning
//

// ***************************************************************************

// EOF
<|endoftext|>


<commit_before>//======================================================================
//-----------------------------------------------------------------------
/**
 * @file        printers_tests.cpp
 * @brief       iutest_printers.hpp テスト
 *
 * @author      t.shirayanagi
 * @par         copyright
 * Copyright (C) 2012-2019, Takazumi Shirayanagi\n
 * This software is released under the new BSD License,
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================

//======================================================================
// include
#include <vector>
#include "iutest.hpp"
#include "logger_tests.hpp"

#ifdef UNICODE
int wmain(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
    IUTEST_INIT(&argc, argv);
    return IUTEST_RUN_ALL_TESTS();
}

struct Bar
{
    int x, y, z;
    bool operator == (const Bar& rhs) const
    {
        return x == rhs.x && y == rhs.y && z == rhs.z;
    }
};

::iutest::iu_ostream& operator << (::iutest::iu_ostream& os, const Bar& bar)
{
    IUTEST_ADD_FAILURE();
    return os << "X:" << bar.x << " Y:" << bar.y << " Z:" << bar.z;
}

void PrintTo(const Bar& bar, ::iutest::iu_ostream* os)
{
    *os << "x:" << bar.x << " y:" << bar.y << " z:" << bar.z;
}

IUTEST(PrintToTest, Bar)
{
    Bar bar = {0, 1, 2};
    LogChecker ck("x:0 y:1 z:2");
    IUTEST_SUCCEED() << ::iutest::PrintToString(bar);
}

#if !defined(IUTEST_USE_GTEST)

IUTEST(PrintToTest, IutestAnyNotInitialized)
{
    ::iutest::any a;
#if !defined(IUTEST_NO_ARGUMENT_DEPENDENT_LOOKUP)
    LogChecker ck("empty");
#else
    LogChecker ck("8-Byte object < 00 00 00 00 00 00 00 00 >");
#endif
    IUTEST_SUCCEED() << ::iutest::PrintToString(a);
}

IUTEST(PrintToTest, IutestAnyString)
{
    ::iutest::any a = "any-test";
#if !defined(IUTEST_NO_ARGUMENT_DEPENDENT_LOOKUP)
    LogChecker ck("any-test");
#else
    LogChecker ck("8-Byte object");
#endif
    IUTEST_SUCCEED() << ::iutest::PrintToString(a);
}

struct BigVar
{
    int big[10];
    BigVar() { memset(big, 0, sizeof(big)); }
    operator ::iutest::BiggestInt () const
    {
        return 42;
    }
};

IUTEST(PrintToTest, BigVar)
{
    BigVar bigvar;
#if !defined(IUTEST_NO_ARGUMENT_DEPENDENT_LOOKUP)
    LogChecker ck("42");
#else
    LogChecker ck("40-Byte object < 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... >");
#endif
    IUTEST_SUCCEED() << ::iutest::PrintToString(bigvar);
}
#endif

#if IUTEST_HAS_TYPED_TEST

template<typename T>
class TypedPrintToTest : public ::iutest::Test {};
typedef ::iutest::Types<char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, int*> PrintStringTestTypes;
IUTEST_TYPED_TEST_CASE(TypedPrintToTest, PrintStringTestTypes);

IUTEST_TYPED_TEST(TypedPrintToTest, Print)
{
    TypeParam a = 0;
    TypeParam& b = a;
    const TypeParam c = a;
    const volatile TypeParam d = a;

    IUTEST_SUCCEED() << ::iutest::PrintToString(a);
    IUTEST_SUCCEED() << ::iutest::PrintToString(b);
    IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    IUTEST_SUCCEED() << ::iutest::PrintToString(d);
}

#endif

IUTEST(PrintToTest, RawArray)
{
    {
        unsigned char a[3] = {0, 1, 2};
        const unsigned char b[3] = {0, 1, 2};
        const volatile unsigned char c[3] = {0, 1, 2};
        volatile unsigned char d[3] = {0, 1, 2};

        IUTEST_SUCCEED() << ::iutest::PrintToString(a);
        IUTEST_SUCCEED() << ::iutest::PrintToString(b);
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
        IUTEST_SUCCEED() << ::iutest::PrintToString(d);
    }
    {
        char a[3] = {0, 1, 2};
        const char b[3] = {0, 1, 2};
        const volatile char c[3] = {0, 1, 2};
        volatile char d[3] = {0, 1, 2};

        IUTEST_SUCCEED() << ::iutest::PrintToString(a);
        IUTEST_SUCCEED() << ::iutest::PrintToString(b);
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
        IUTEST_SUCCEED() << ::iutest::PrintToString(d);
    }
}

IUTEST(PrintToTest, Std)
{
    const int a[] = {0, 1, 2};
    ::std::pair<int, int> p(0, 1);
    ::std::vector<int> v(a, a+(sizeof(a)/sizeof(a[0])));

    {
        LogChecker ck("0, 1");
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
    {
        LogChecker ck("{ 0, 1, 2 }");
        IUTEST_SUCCEED() << ::iutest::PrintToString(v);
    }
}

IUTEST(PrintToTest, Null)
{
    {
        LogChecker ck("(null)");
        void* p = NULL;
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
    {
        LogChecker ck("(null)");
        void* p = NULL;
        IUTEST_SUCCEED() << p;
    }
}

#if IUTEST_HAS_IOMANIP
IUTEST(PrintToTest, Iomanip)
{
    IUTEST_SUCCEED() << ::std::endl;
    IUTEST_SUCCEED() << ::std::ends;
}
#endif

IUTEST(PrintToTest, WideString)
{
    {
        LogChecker ck("Test");
        IUTEST_SUCCEED() << ::iutest::PrintToString(L"Test");
    }
    {
        LogChecker ck("\\0");
        wchar_t c = 0;
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("10");
        wchar_t c = L'\n';
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("\'A\'");
        wchar_t c = L'A';
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("(null)");
        wchar_t* p = NULL;
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
}

IUTEST(PrintToTest, String)
{
    {
        LogChecker ck("Test");
        IUTEST_SUCCEED() << ::iutest::PrintToString("Test");
    }
    {
        LogChecker ck("\\0");
        char c = 0;
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("10");
        char c = '\n';
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("\'A\'");
        char c = 'A';
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("(null)");
        char* p = NULL;
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
}

#if IUTEST_HAS_CHAR16_T
IUTEST(PrintToTest, U16String)
{
    IUTEST_SUCCEED() << ::iutest::PrintToString(u"Test");
    {
        LogChecker ck("(null)");
        char16_t* p = NULL;
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
}
#endif

#if IUTEST_HAS_CHAR32_T
IUTEST(PrintToTest, U32String)
{
    IUTEST_SUCCEED() << ::iutest::PrintToString(U"Test");
    {
        LogChecker ck("(null)");
        char32_t* p = NULL;
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
}
#endif

struct Point0
{
    unsigned int x, y;
};
struct Point1
{
    int x, y;
};
struct Point2
{
    int x, y;
};

::iutest::iu_ostream& operator << (::iutest::iu_ostream& os, const Point1& x)
{
    return os << x.x << ", " << x.y << "(operator overload)";
}

void PrintTo(const Point2& x, ::iutest::iu_ostream* os)
{
    *os << x.x << ", " << x.y << "(function overload)";
}

#if IUTEST_HAS_PRINT_TO

IUTEST(PrintToTest, Overload)
{
    Point0 p0 = { 0x12345678, 0x9ABCDEF0 };
    Point1 p1 = {0, 0};
    Point2 p2 = {1, 1};
    {
        LogChecker ck("8-Byte object <");
        IUTEST_SUCCEED() << ::iutest::PrintToString(p0);
    }
    {
        LogChecker ck("(operator overload)");
        IUTEST_SUCCEED() << ::iutest::PrintToString(p1);
    }
    {
        LogChecker ck("(function overload)");
        IUTEST_SUCCEED() << ::iutest::PrintToString(p2);
    }
}

#endif

struct Hoge {
    int a[256];
};
IUTEST(PrintToTest, MaxElem)
{
    Hoge hoge = { { 0 } };
    {
        LogChecker ck(" ...");
        IUTEST_SUCCEED() << ::iutest::PrintToString(hoge);
    }
    {
        LogChecker ck(", ...");
        IUTEST_SUCCEED() << ::iutest::PrintToString(hoge.a);
    }
    {
        ::std::vector<int> v(hoge.a, hoge.a+256);
        LogChecker ck(", ...");
        IUTEST_SUCCEED() << ::iutest::PrintToString(v);
    }
}

#if IUTEST_HAS_NULLPTR
IUTEST(PrintToTest, Nullptr)
{
    LogChecker ck("nullptr");
    IUTEST_SUCCEED() << ::iutest::PrintToString(nullptr);
}
#endif

#if IUTEST_HAS_TUPLE
IUTEST(PrintToTest, Tuple)
{
    LogChecker ck("false, 100, 'a'");
    ::iutest::tuples::tuple<bool, int, char> t(false, 100, 'a');

    IUTEST_SUCCEED() << ::iutest::PrintToString(t);
}
#endif

<commit_msg>update test<commit_after>//======================================================================
//-----------------------------------------------------------------------
/**
 * @file        printers_tests.cpp
 * @brief       iutest_printers.hpp テスト
 *
 * @author      t.shirayanagi
 * @par         copyright
 * Copyright (C) 2012-2019, Takazumi Shirayanagi\n
 * This software is released under the new BSD License,
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================

//======================================================================
// include
#include <vector>
#include "iutest.hpp"
#include "logger_tests.hpp"

#ifdef UNICODE
int wmain(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
    IUTEST_INIT(&argc, argv);
    return IUTEST_RUN_ALL_TESTS();
}

struct Bar
{
    int x, y, z;
    bool operator == (const Bar& rhs) const
    {
        return x == rhs.x && y == rhs.y && z == rhs.z;
    }
};

::iutest::iu_ostream& operator << (::iutest::iu_ostream& os, const Bar& bar)
{
    IUTEST_ADD_FAILURE();
    return os << "X:" << bar.x << " Y:" << bar.y << " Z:" << bar.z;
}

void PrintTo(const Bar& bar, ::iutest::iu_ostream* os)
{
    *os << "x:" << bar.x << " y:" << bar.y << " z:" << bar.z;
}

IUTEST(PrintToTest, Bar)
{
    Bar bar = {0, 1, 2};
    LogChecker ck("x:0 y:1 z:2");
    IUTEST_SUCCEED() << ::iutest::PrintToString(bar);
}

#if !defined(IUTEST_USE_GTEST)

IUTEST(PrintToTest, IutestAnyNotInitialized)
{
    ::iutest::any a;
#if !defined(IUTEST_NO_ARGUMENT_DEPENDENT_LOOKUP)
    LogChecker ck("empty");
#else
    LogChecker ck("8-Byte object < 00 00 00 00 00 00 00 00 >");
#endif
    IUTEST_SUCCEED() << ::iutest::PrintToString(a);
}

IUTEST(PrintToTest, IutestAnyString)
{
    ::iutest::any a = "any-test";
#if !defined(IUTEST_NO_ARGUMENT_DEPENDENT_LOOKUP)
    LogChecker ck("any-test");
#else
    LogChecker ck("8-Byte object");
#endif
    IUTEST_SUCCEED() << ::iutest::PrintToString(a);
}

struct BigVar
{
    int big[10];
    BigVar() { memset(big, 0, sizeof(big)); }
    operator ::iutest::BiggestInt () const
    {
        return 42;
    }
};

IUTEST(PrintToTest, BigVar)
{
    BigVar bigvar;
#if !defined(IUTEST_NO_ARGUMENT_DEPENDENT_LOOKUP)
    LogChecker ck("42");
#else
    LogChecker ck("40-Byte object < 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... >");
#endif
    IUTEST_SUCCEED() << ::iutest::PrintToString(bigvar);
}
#endif

#if IUTEST_HAS_TYPED_TEST

template<typename T>
class TypedPrintToTest : public ::iutest::Test {};
typedef ::iutest::Types<char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, int*> PrintStringTestTypes;
IUTEST_TYPED_TEST_CASE(TypedPrintToTest, PrintStringTestTypes);

IUTEST_TYPED_TEST(TypedPrintToTest, Print)
{
    TypeParam a = 0;
    TypeParam& b = a;
    const TypeParam c = a;
    const volatile TypeParam d = a;

    IUTEST_SUCCEED() << ::iutest::PrintToString(a);
    IUTEST_SUCCEED() << ::iutest::PrintToString(b);
    IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    IUTEST_SUCCEED() << ::iutest::PrintToString(d);
}

#endif

IUTEST(PrintToTest, RawArray)
{
    {
        unsigned char a[3] = {0, 1, 2};
        const unsigned char b[3] = {0, 1, 2};
        const volatile unsigned char c[3] = {0, 1, 2};
        volatile unsigned char d[3] = {0, 1, 2};

        IUTEST_SUCCEED() << ::iutest::PrintToString(a);
        IUTEST_SUCCEED() << ::iutest::PrintToString(b);
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
        IUTEST_SUCCEED() << ::iutest::PrintToString(d);
    }
    {
        char a[3] = {0, 1, 2};
        const char b[3] = {0, 1, 2};
        const volatile char c[3] = {0, 1, 2};
        volatile char d[3] = {0, 1, 2};

        IUTEST_SUCCEED() << ::iutest::PrintToString(a);
        IUTEST_SUCCEED() << ::iutest::PrintToString(b);
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
        IUTEST_SUCCEED() << ::iutest::PrintToString(d);
    }
}

IUTEST(PrintToTest, Std)
{
    const int a[] = {0, 1, 2};
    ::std::pair<int, int> p(0, 1);
    ::std::vector<int> v(a, a+(sizeof(a)/sizeof(a[0])));

    {
        LogChecker ck("0, 1");
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
    {
        LogChecker ck("{ 0, 1, 2 }");
        IUTEST_SUCCEED() << ::iutest::PrintToString(v);
    }
}

IUTEST(PrintToTest, Null)
{
    {
        LogChecker ck("(null)");
        void* p = NULL;
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
    {
        LogChecker ck("(null)");
        void* p = NULL;
        IUTEST_SUCCEED() << p;
    }
}

#if IUTEST_HAS_IOMANIP
IUTEST(PrintToTest, Iomanip)
{
    IUTEST_SUCCEED() << ::std::endl;
    IUTEST_SUCCEED() << ::std::ends;
}
#endif

IUTEST(PrintToTest, WideString)
{
    {
        LogChecker ck("Test");
        IUTEST_SUCCEED() << ::iutest::PrintToString(L"Test");
    }
    {
        LogChecker ck("\\0");
        wchar_t c = 0;
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("10");
        wchar_t c = L'\n';
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("\'A\'");
        wchar_t c = L'A';
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("(null)");
        wchar_t* p = NULL;
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
}

IUTEST(PrintToTest, String)
{
    {
        LogChecker ck("Test");
        IUTEST_SUCCEED() << ::iutest::PrintToString("Test");
    }
    {
        LogChecker ck("\\0");
        char c = 0;
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("10");
        char c = '\n';
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("\'A\'");
        char c = 'A';
        IUTEST_SUCCEED() << ::iutest::PrintToString(c);
    }
    {
        LogChecker ck("(null)");
        char* p = NULL;
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
}

#if IUTEST_HAS_CHAR16_T
IUTEST(PrintToTest, U16String)
{
    IUTEST_SUCCEED() << ::iutest::PrintToString(u"Test");
    {
        LogChecker ck("(null)");
        char16_t* p = NULL;
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
}
#endif

#if IUTEST_HAS_CHAR32_T
IUTEST(PrintToTest, U32String)
{
    IUTEST_SUCCEED() << ::iutest::PrintToString(U"Test");
    {
        LogChecker ck("(null)");
        char32_t* p = NULL;
        IUTEST_SUCCEED() << ::iutest::PrintToString(p);
    }
}
#endif

struct Point0
{
    unsigned int x, y;
};
struct Point1
{
    int x, y;
};
struct Point2
{
    int x, y;
};

::iutest::iu_ostream& operator << (::iutest::iu_ostream& os, const Point1& x)
{
    return os << x.x << ", " << x.y << "(operator overload)";
}

void PrintTo(const Point2& x, ::iutest::iu_ostream* os)
{
    *os << x.x << ", " << x.y << "(function overload)";
}

#if IUTEST_HAS_PRINT_TO

IUTEST(PrintToTest, Overload)
{
    Point0 p0 = { 0x12345678, 0x9ABCDEF0 };
    Point1 p1 = {0, 0};
    Point2 p2 = {1, 1};
    {
        LogChecker ck("8-Byte object <");
        IUTEST_SUCCEED() << ::iutest::PrintToString(p0);
    }
    {
        LogChecker ck("(operator overload)");
        IUTEST_SUCCEED() << ::iutest::PrintToString(p1);
    }
    {
        LogChecker ck("(function overload)");
        IUTEST_SUCCEED() << ::iutest::PrintToString(p2);
    }
}

#endif

struct Hoge {
    int a[256];
};
IUTEST(PrintToTest, ThresholdObjectSize)
{
    Hoge hoge = { { 0 } };
    LogChecker ck("< 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... >");
    IUTEST_SUCCEED() << ::iutest::PrintToString(hoge);
}
IUTEST(PrintToTest, ThresholdArraySize)
{
    int a[256] = { 0 };
    LogChecker ck("{ 0, 0, 0, 0, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0, 0 }");
    IUTEST_SUCCEED() << ::iutest::PrintToString(a);
}
IUTEST(PrintToTest, ThresholdContainerSizer)
{
    int a[256] = { 0 };
    ::std::vector<int> v(a, a+256);
    LogChecker ck("{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... }");
    IUTEST_SUCCEED() << ::iutest::PrintToString(v);
}

#if IUTEST_HAS_NULLPTR
IUTEST(PrintToTest, Nullptr)
{
    LogChecker ck("nullptr");
    IUTEST_SUCCEED() << ::iutest::PrintToString(nullptr);
}
#endif

#if IUTEST_HAS_TUPLE
IUTEST(PrintToTest, Tuple)
{
    LogChecker ck("false, 100, 'a'");
    ::iutest::tuples::tuple<bool, int, char> t(false, 100, 'a');

    IUTEST_SUCCEED() << ::iutest::PrintToString(t);
}
#endif

<|endoftext|>


<commit_before>// Test that out-of-scope local variables are ignored by LSan.
// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0:use_stacks=1"
// RUN: %clangxx_lsan %s -o %t
// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
// RUN: LSAN_OPTIONS=$LSAN_BASE":exitcode=0" %run %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s

#include <stdio.h>
#include <stdlib.h>
#include "sanitizer_common/print_address.h"

void **pp;

// Put pointer far enough on the stack that LSan has space to run in without
// overwriting it.
// Hopefully the argument p will be passed on a register, saving us from false
// negatives.
__attribute__((noinline))
void *PutPointerOnStaleStack(void *p) {
  void *locals[2048];
  locals[0] = p;
  pp = &locals[0];
  print_address("Test alloc: ", 1, locals[0]);
  return 0;
}

int main() {
  PutPointerOnStaleStack(malloc(1337));
  return 0;
}

// This must run after LSan, to ensure LSan didn't overwrite the pointer before
// it had a chance to see it. If LSan is invoked with atexit(), this works.
// Otherwise, we need a different method.
__attribute__((destructor))
__attribute__((no_sanitize_address))
void ConfirmPointerHasSurvived() {
  print_address("Value after LSan: ", 1, *pp);
}
// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]]
// CHECK-sanity: Test alloc: [[ADDR:0x[0-9,a-f]+]]
// CHECK: LeakSanitizer: detected memory leaks
// CHECK: [[ADDR]] (1337 bytes)
// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
// CHECK-sanity: Value after LSan: [[ADDR]]
<commit_msg>[lsan] Disable stale_stack_leak.cc testcase on x86<commit_after>// Test that out-of-scope local variables are ignored by LSan.
// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_registers=0:use_stacks=1"
// RUN: %clangxx_lsan %s -o %t
// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
// RUN: LSAN_OPTIONS=$LSAN_BASE":exitcode=0" %run %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s
//
// x86 passes parameters through stack that may lead to false negatives
// UNSPPORTED: x86

#include <stdio.h>
#include <stdlib.h>
#include "sanitizer_common/print_address.h"

void **pp;

// Put pointer far enough on the stack that LSan has space to run in without
// overwriting it.
// Hopefully the argument p will be passed on a register, saving us from false
// negatives.
__attribute__((noinline))
void *PutPointerOnStaleStack(void *p) {
  void *locals[2048];
  locals[0] = p;
  pp = &locals[0];
  print_address("Test alloc: ", 1, locals[0]);
  return 0;
}

int main() {
  PutPointerOnStaleStack(malloc(1337));
  return 0;
}

// This must run after LSan, to ensure LSan didn't overwrite the pointer before
// it had a chance to see it. If LSan is invoked with atexit(), this works.
// Otherwise, we need a different method.
__attribute__((destructor))
__attribute__((no_sanitize_address))
void ConfirmPointerHasSurvived() {
  print_address("Value after LSan: ", 1, *pp);
}
// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]]
// CHECK-sanity: Test alloc: [[ADDR:0x[0-9,a-f]+]]
// CHECK: LeakSanitizer: detected memory leaks
// CHECK: [[ADDR]] (1337 bytes)
// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
// CHECK-sanity: Value after LSan: [[ADDR]]
<|endoftext|>


<commit_before>#include <sys/stat.h>
#include "storing.hh"
#include "StoreTarget.h"
#include "../Util2.h"
#include "../InputFileStream.h"

namespace Moses2
{

BinaryFileWriter::BinaryFileWriter (std::string basepath) : os ((basepath + "/binfile.dat").c_str(), std::ios::binary)
{
  binfile.reserve(10000); //Reserve part of the vector to avoid realocation
  it = binfile.begin();
  dist_from_start = 0; //Initialize variables
  extra_counter = 0;
}

void BinaryFileWriter::write (std::vector<unsigned char> * bytes)
{
  binfile.insert(it, bytes->begin(), bytes->end()); //Insert the bytes
  //Keep track of the offsets
  it += bytes->size();
  dist_from_start = distance(binfile.begin(),it);
  //Flush the vector to disk every once in a while so that we don't consume too much ram
  if (dist_from_start > 9000) {
    flush();
  }
}

void BinaryFileWriter::flush ()
{
  //Cast unsigned char to char before writing...
  os.write((char *)&binfile[0], dist_from_start);
  //Clear the vector:
  binfile.clear();
  binfile.reserve(10000);
  extra_counter += dist_from_start; //Keep track of the total number of bytes.
  it = binfile.begin(); //Reset iterator
  dist_from_start = distance(binfile.begin(),it); //Reset dist from start
}

BinaryFileWriter::~BinaryFileWriter ()
{
  os.close();
  binfile.clear();
}

void createProbingPT(
		const std::string &phrasetable_path,
		const std::string &basepath,
        int num_scores,
		int num_lex_scores,
		bool log_prob,
		int max_cache_size)
{
  std::cerr << "Starting..." << std::endl;

  //Get basepath and create directory if missing
  mkdir(basepath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);

  //Set up huffman and serialize decoder maps.
  Huffman huffmanEncoder(phrasetable_path.c_str()); //initialize
  huffmanEncoder.assign_values();
  huffmanEncoder.produce_lookups();
  huffmanEncoder.serialize_maps(basepath.c_str());

  StoreTarget storeTarget(basepath);

  //Get uniq lines:
  unsigned long uniq_entries = countUniqueSource(phrasetable_path);

  //Source phrase vocabids
  std::map<uint64_t, std::string> source_vocabids;

  //Read the file
  util::FilePiece filein(phrasetable_path.c_str());

  //Init the probing hash table
  size_t size = Table::Size(uniq_entries, 1.2);
  char * mem = new char[size];
  memset(mem, 0, size);
  Table table(mem, size);

  BinaryFileWriter binfile(basepath); //Init the binary file writer.

  std::priority_queue<CacheItem*, std::vector<CacheItem*>, CacheItemOrderer> cache;
  float totalSourceCount = 0;

  //Keep track of the size of each group of target phrases
  uint64_t entrystartidx = 0;
  size_t line_num = 0;

  //Read everything and processs
  std::string prevSource;
  while(true) {
    try {
      //Process line read
      line_text line;
      line = splitLine(filein.ReadLine());

      ++line_num;
      if (line_num % 1000000 == 0) {
    	  std::cerr << line_num << " " << std::flush;
      }

      //Add source phrases to vocabularyIDs
      add_to_map(&source_vocabids, line.source_phrase);

      if ((binfile.dist_from_start + binfile.extra_counter) == 0) {
    	prevSource = line.source_phrase.as_string(); //For the first iteration assume the previous line is
      } //The same as this one.

      if (line.source_phrase != prevSource) {

        //Create a new entry even

        // save
        uint64_t targetInd = storeTarget.Save();

          // next line
      	storeTarget.Append(line, log_prob);

        //Create an entry for the previous source phrase:
        Entry pesho;
        pesho.value = entrystartidx;
        pesho.targetInd = targetInd;
        //The key is the sum of hashes of individual words bitshifted by their position in the phrase.
        //Probably not entirerly correct, but fast and seems to work fine in practise.
        pesho.key = 0;
        std::vector<uint64_t> vocabid_source = getVocabIDs(prevSource);
        for (int i = 0; i < vocabid_source.size(); i++) {
          pesho.key += (vocabid_source[i] << i);
        }
        pesho.bytes_toread = binfile.dist_from_start + binfile.extra_counter - entrystartidx;

        //Put into table
        table.Insert(pesho);

        entrystartidx = binfile.dist_from_start + binfile.extra_counter; //Designate start idx for new entry

        //Encode a line and write it to disk.
        std::vector<unsigned char> encoded_line = huffmanEncoder.full_encode_line(line, log_prob);
        binfile.write(&encoded_line);

        // update cache
        if (max_cache_size) {
			std::string countStr = line.counts.as_string();
			countStr = Trim(countStr);
			if (!countStr.empty()) {
				std::vector<float> toks = Tokenize<float>(countStr);

				if (toks.size() >= 2) {
					totalSourceCount += toks[1];
					CacheItem *item = new CacheItem(Trim(line.source_phrase.as_string()), toks[1]);
					cache.push(item);

					if (max_cache_size > 0 && cache.size() > max_cache_size) {
						cache.pop();
					}
				}
			}
        }

        //Set prevLine
        prevSource = line.source_phrase.as_string();

      } else {
        //If we still have the same line, just append to it:
    	storeTarget.Append(line, log_prob);

        std::vector<unsigned char> encoded_line = huffmanEncoder.full_encode_line(line, log_prob);
        binfile.write(&encoded_line);
      }

    } catch (util::EndOfFileException e) {
      std::cerr << "Reading phrase table finished, writing remaining files to disk." << std::endl;
      binfile.flush();

      //After the final entry is constructed we need to add it to the phrase_table
      //Create an entry for the previous source phrase:
      uint64_t targetInd = storeTarget.Save();

      Entry pesho;
      pesho.value = entrystartidx;
      pesho.targetInd = targetInd;

      //The key is the sum of hashes of individual words. Probably not entirerly correct, but fast
      pesho.key = 0;
      std::vector<uint64_t> vocabid_source = getVocabIDs(prevSource);
      for (int i = 0; i < vocabid_source.size(); i++) {
        pesho.key += (vocabid_source[i] << i);
      }
      pesho.bytes_toread = binfile.dist_from_start + binfile.extra_counter - entrystartidx;
      //Put into table
      table.Insert(pesho);

      break;
    }
  }

  serialize_table(mem, size, (basepath + "/probing_hash.dat"));

  serialize_map(&source_vocabids, (basepath + "/source_vocabids"));

  serialize_cache(cache, (basepath + "/cache"), totalSourceCount);

  delete[] mem;

  //Write configfile
  std::ofstream configfile;
  configfile.open((basepath + "/config").c_str());
  configfile << API_VERSION << '\n';
  configfile << uniq_entries << '\n';
  configfile << num_scores << '\n';
  configfile << num_lex_scores << '\n';
  configfile << log_prob << '\n';
  configfile.close();
}

size_t countUniqueSource(const std::string &path)
{
	size_t ret = 0;
	InputFileStream strme(path);

	std::string line, prevSource;
	while (std::getline(strme, line)) {
		std::vector<std::string> toks = TokenizeMultiCharSeparator(line, "|||");
		assert(toks.size() == 0);

		if (prevSource != toks[0]) {
			prevSource = toks[0];
			++ret;
		}
	}

	return ret;
}

void serialize_cache(std::priority_queue<CacheItem*, std::vector<CacheItem*>, CacheItemOrderer> &cache,
		const std::string &path,
		float totalSourceCount)
{
  std::vector<const CacheItem*> vec(cache.size());

  size_t ind = cache.size() - 1;
  while (!cache.empty()) {
	  const CacheItem *item = cache.top();
	  vec[ind] = item;
	  cache.pop();
	  --ind;
  }

  std::ofstream os (path.c_str());

  os << totalSourceCount << std::endl;
  for (size_t i = 0; i < vec.size(); ++i) {
	  const CacheItem *item = vec[i];
	  os << item->count << "\t" << item->source << std::endl;
	  delete item;
  }

  os.close();
}

}

<commit_msg>just store prev source, not whole line<commit_after>#include <sys/stat.h>
#include "storing.hh"
#include "StoreTarget.h"
#include "../Util2.h"
#include "../InputFileStream.h"

namespace Moses2
{

BinaryFileWriter::BinaryFileWriter (std::string basepath) : os ((basepath + "/binfile.dat").c_str(), std::ios::binary)
{
  binfile.reserve(10000); //Reserve part of the vector to avoid realocation
  it = binfile.begin();
  dist_from_start = 0; //Initialize variables
  extra_counter = 0;
}

void BinaryFileWriter::write (std::vector<unsigned char> * bytes)
{
  binfile.insert(it, bytes->begin(), bytes->end()); //Insert the bytes
  //Keep track of the offsets
  it += bytes->size();
  dist_from_start = distance(binfile.begin(),it);
  //Flush the vector to disk every once in a while so that we don't consume too much ram
  if (dist_from_start > 9000) {
    flush();
  }
}

void BinaryFileWriter::flush ()
{
  //Cast unsigned char to char before writing...
  os.write((char *)&binfile[0], dist_from_start);
  //Clear the vector:
  binfile.clear();
  binfile.reserve(10000);
  extra_counter += dist_from_start; //Keep track of the total number of bytes.
  it = binfile.begin(); //Reset iterator
  dist_from_start = distance(binfile.begin(),it); //Reset dist from start
}

BinaryFileWriter::~BinaryFileWriter ()
{
  os.close();
  binfile.clear();
}

void createProbingPT(
		const std::string &phrasetable_path,
		const std::string &basepath,
        int num_scores,
		int num_lex_scores,
		bool log_prob,
		int max_cache_size)
{
  std::cerr << "Starting..." << std::endl;

  //Get basepath and create directory if missing
  mkdir(basepath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);

  //Set up huffman and serialize decoder maps.
  Huffman huffmanEncoder(phrasetable_path.c_str()); //initialize
  huffmanEncoder.assign_values();
  huffmanEncoder.produce_lookups();
  huffmanEncoder.serialize_maps(basepath.c_str());

  StoreTarget storeTarget(basepath);

  //Get uniq lines:
  unsigned long uniq_entries = countUniqueSource(phrasetable_path);

  //Source phrase vocabids
  std::map<uint64_t, std::string> source_vocabids;

  //Read the file
  util::FilePiece filein(phrasetable_path.c_str());

  //Init the probing hash table
  size_t size = Table::Size(uniq_entries, 1.2);
  char * mem = new char[size];
  memset(mem, 0, size);
  Table table(mem, size);

  BinaryFileWriter binfile(basepath); //Init the binary file writer.

  std::priority_queue<CacheItem*, std::vector<CacheItem*>, CacheItemOrderer> cache;
  float totalSourceCount = 0;

  //Keep track of the size of each group of target phrases
  uint64_t entrystartidx = 0;
  size_t line_num = 0;

  //Read everything and processs
  std::string prevSource;
  while(true) {
    try {
      //Process line read
      line_text line;
      line = splitLine(filein.ReadLine());

      ++line_num;
      if (line_num % 1000000 == 0) {
    	  std::cerr << line_num << " " << std::flush;
      }

      //Add source phrases to vocabularyIDs
      add_to_map(&source_vocabids, line.source_phrase);

      if (prevSource.empty()) {
    	  // 1st line
    	  prevSource = line.source_phrase.as_string();
          storeTarget.Append(line, log_prob);
      }
      else if (prevSource == line.source_phrase) {
          //If we still have the same line, just append to it:
    	  storeTarget.Append(line, log_prob);
      }
      else {
    	assert(prevSource != line.source_phrase);

        //Create a new entry even

        // save
        uint64_t targetInd = storeTarget.Save();

          // next line
      	storeTarget.Append(line, log_prob);

        //Create an entry for the previous source phrase:
        Entry pesho;
        pesho.value = entrystartidx;
        pesho.targetInd = targetInd;
        //The key is the sum of hashes of individual words bitshifted by their position in the phrase.
        //Probably not entirerly correct, but fast and seems to work fine in practise.
        pesho.key = 0;
        std::vector<uint64_t> vocabid_source = getVocabIDs(prevSource);
        for (int i = 0; i < vocabid_source.size(); i++) {
          pesho.key += (vocabid_source[i] << i);
        }
        pesho.bytes_toread = binfile.dist_from_start + binfile.extra_counter - entrystartidx;

        //Put into table
        table.Insert(pesho);

        entrystartidx = binfile.dist_from_start + binfile.extra_counter; //Designate start idx for new entry

        //Encode a line and write it to disk.
        std::vector<unsigned char> encoded_line = huffmanEncoder.full_encode_line(line, log_prob);
        binfile.write(&encoded_line);

        // update cache
        if (max_cache_size) {
			std::string countStr = line.counts.as_string();
			countStr = Trim(countStr);
			if (!countStr.empty()) {
				std::vector<float> toks = Tokenize<float>(countStr);

				if (toks.size() >= 2) {
					totalSourceCount += toks[1];
					CacheItem *item = new CacheItem(Trim(line.source_phrase.as_string()), toks[1]);
					cache.push(item);

					if (max_cache_size > 0 && cache.size() > max_cache_size) {
						cache.pop();
					}
				}
			}
        }

        //Set prevLine
        prevSource = line.source_phrase.as_string();

      }

    } catch (util::EndOfFileException e) {
      std::cerr << "Reading phrase table finished, writing remaining files to disk." << std::endl;
      binfile.flush();

      //After the final entry is constructed we need to add it to the phrase_table
      //Create an entry for the previous source phrase:
      uint64_t targetInd = storeTarget.Save();

      Entry pesho;
      pesho.value = entrystartidx;
      pesho.targetInd = targetInd;

      //The key is the sum of hashes of individual words. Probably not entirerly correct, but fast
      pesho.key = 0;
      std::vector<uint64_t> vocabid_source = getVocabIDs(prevSource);
      for (int i = 0; i < vocabid_source.size(); i++) {
        pesho.key += (vocabid_source[i] << i);
      }
      pesho.bytes_toread = binfile.dist_from_start + binfile.extra_counter - entrystartidx;
      //Put into table
      table.Insert(pesho);

      break;
    }
  }

  serialize_table(mem, size, (basepath + "/probing_hash.dat"));

  serialize_map(&source_vocabids, (basepath + "/source_vocabids"));

  serialize_cache(cache, (basepath + "/cache"), totalSourceCount);

  delete[] mem;

  //Write configfile
  std::ofstream configfile;
  configfile.open((basepath + "/config").c_str());
  configfile << API_VERSION << '\n';
  configfile << uniq_entries << '\n';
  configfile << num_scores << '\n';
  configfile << num_lex_scores << '\n';
  configfile << log_prob << '\n';
  configfile.close();
}

size_t countUniqueSource(const std::string &path)
{
	size_t ret = 0;
	InputFileStream strme(path);

	std::string line, prevSource;
	while (std::getline(strme, line)) {
		std::vector<std::string> toks = TokenizeMultiCharSeparator(line, "|||");
		assert(toks.size() == 0);

		if (prevSource != toks[0]) {
			prevSource = toks[0];
			++ret;
		}
	}

	return ret;
}

void serialize_cache(std::priority_queue<CacheItem*, std::vector<CacheItem*>, CacheItemOrderer> &cache,
		const std::string &path,
		float totalSourceCount)
{
  std::vector<const CacheItem*> vec(cache.size());

  size_t ind = cache.size() - 1;
  while (!cache.empty()) {
	  const CacheItem *item = cache.top();
	  vec[ind] = item;
	  cache.pop();
	  --ind;
  }

  std::ofstream os (path.c_str());

  os << totalSourceCount << std::endl;
  for (size_t i = 0; i < vec.size(); ++i) {
	  const CacheItem *item = vec[i];
	  os << item->count << "\t" << item->source << std::endl;
	  delete item;
  }

  os.close();
}

}

<|endoftext|>