<commit_before>// $Id$

// The libMesh Finite Element Library.
// Copyright (C) 2002-2008 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes

// Local includes
#include "libmesh_config.h"
#include "boundary_info.h"
#include "boundary_mesh.h"
#include "elem.h"
#include "mesh_data.h"
#include "parallel.h"

//------------------------------------------------------
// BoundaryInfo static member initializations
const short int BoundaryInfo::invalid_id = -1234;

//------------------------------------------------------
// BoundaryInfo functions
BoundaryInfo::BoundaryInfo(const MeshBase& m) :
  _mesh (m)
{
}

BoundaryInfo::~BoundaryInfo()
{
  this->clear();
}

void BoundaryInfo::clear()
{
  _boundary_node_id.clear();
  _boundary_side_id.clear();
  _boundary_ids.clear();
}

void BoundaryInfo::sync(BoundaryMesh& boundary_mesh,
			MeshData*     boundary_mesh_data,
			MeshData*     this_mesh_data)
{
  boundary_mesh.clear();

  /**
   * Re-create the boundary mesh.
   */

  std::map<unsigned int, unsigned int> new_node_numbers;

  boundary_mesh.set_n_subdomains() = this->n_boundary_ids();

  // Add sides to the structure.
  std::map<short int, unsigned int> id_map;

  // Original Code
  //     unsigned int cnt = 0;
  //     for (std::set<short int>::iterator pos = boundary_ids.begin();
  // 	 pos != boundary_ids.end(); ++pos)
  //       id_map[*pos] = cnt++;

  //     id_map[invalid_id] = cnt;

  // New code
  // Here we need to use iota() once it is in the
  // Utility namespace.
  std::for_each(_boundary_ids.begin(),
		_boundary_ids.end(),
		Fill(id_map));

  boundary_mesh.set_n_subdomains() = id_map.size();

  // Make individual copies of all the nodes in the current mesh
  // and add them to the boundary mesh.  Yes, this is overkill because
  // all of the current mesh nodes will not end up in the the boundary
  // mesh.  These nodes can be trimmed later via a call to prepare_for_use().
  {
    libmesh_assert (boundary_mesh.n_nodes() == 0);
    boundary_mesh.reserve_nodes(_mesh.n_nodes());

    MeshBase::const_node_iterator it  = _mesh.nodes_begin();
    MeshBase::const_node_iterator end = _mesh.nodes_end();

    for(; it != end; ++it)
      {
	const Node* node = *it;
	boundary_mesh.add_point(*node); // calls Node::build(Point, id)
      }
  }

  // Add additional sides that aren't flagged with boundary conditions
  MeshBase::const_element_iterator       el     = _mesh.active_elements_begin();
  const MeshBase::const_element_iterator end_el = _mesh.active_elements_end();

  for ( ; el != end_el; ++el)
    {
      const Elem* elem = *el;

      for (unsigned int s=0; s<elem->n_sides(); s++)
	if (elem->neighbor(s) == NULL) // on the boundary
	  {

	    // Build the side - do not use a "proxy" element here:
	    // This will be going into the BoundaryMesh and needs to
	    // stand on its own.
	    AutoPtr<Elem> side (elem->build_side(s, false));

	    // Get the top-level parent for this element
	    const Elem* top_parent = elem->top_parent();

	    // A convenient typedef
	    typedef
	      std::multimap<const Elem*, std::pair<unsigned short int, short int> >::const_iterator
	      Iter;

	    // Find the right id number for that side
	    std::pair<Iter, Iter> pos = _boundary_side_id.equal_range(top_parent);

	    while (pos.first != pos.second)
	      {
		if (pos.first->second.first == s) // already flagged with a boundary condition
		  {
		    side->subdomain_id() =
		      id_map[pos.first->second.second];

		    side->processor_id() =
		      side->subdomain_id();
		    break;
		  }

		++pos.first;
	      }

	    // either the element wasn't found or side s
	    // doesn't have a boundary condition
	    if (pos.first == pos.second)
	      {
		side->subdomain_id() = id_map[invalid_id];
	      }

	    // Add the side
	    Elem* new_elem = boundary_mesh.add_elem(side.release());

	    // This side's Node pointers still point to the nodes of the  original mesh.
	    // We need to re-point them to the boundary mesh's nodes!  Since we copied *ALL* of
	    // the original mesh's nodes over, we should be guaranteed to have the same ordering.
	    for (unsigned int nn=0; nn<new_elem->n_nodes(); ++nn)
	      {
		// Get the correct node pointer, based on the id()
		Node* new_node = boundary_mesh.node_ptr(new_elem->node(nn));

		// sanity check: be sure that the new Nodes global id really matches
		libmesh_assert (new_node->id() == new_elem->node(nn));

		// Assign the new node pointer
		new_elem->set_node(nn) = new_node;
	      }
	  }
    } // end loop over active elements

  // When desired, copy the MeshData
  // to the boundary_mesh
  if ((boundary_mesh_data != NULL) && (this_mesh_data != NULL))
    boundary_mesh_data->assign(*this_mesh_data);

  // Trim any un-used nodes from the Mesh
  boundary_mesh.prepare_for_use();
}

void BoundaryInfo::add_node(const unsigned int node,
			    const short int id)
{
  this->add_node (_mesh.node_ptr(node), id);
}

void BoundaryInfo::add_node(const Node* node,
			    const short int id)
{
  if (id == invalid_id)
    {
      std::cerr << "ERROR: You may not set a boundary ID of "
		<< invalid_id << std::endl
		<< " That is reserved for internal use.\n"
		<< std::endl;

      libmesh_error();
    }

  _boundary_node_id[node] = id;
  _boundary_ids.insert(id);
}

void BoundaryInfo::add_side(const unsigned int e,
			    const unsigned short int side,
			    const short int id)
{
  this->add_side (_mesh.elem(e), side, id);
}

void BoundaryInfo::add_side(const Elem* elem,
			    const unsigned short int side,
			    const short int id)
{
  libmesh_assert (elem != NULL);

  // Only add BCs for level-0 elements.
  libmesh_assert (elem->level() == 0);

  if (id == invalid_id)
    {
      std::cerr << "ERROR: You may not set a boundary ID of "
		<< invalid_id << std::endl
		<< " That is reserved for internal use.\n"
		<< std::endl;

      libmesh_error();
    }

  std::pair<unsigned short int, short int> p(side,id);
  std::pair<const Elem*, std::pair<unsigned short int, short int> >
    kv (elem, p);

  _boundary_side_id.insert(kv);
  _boundary_ids.insert(id);
}

short int BoundaryInfo::boundary_id(const Node* node) const
{
  std::map<const Node*, short int>::const_iterator
    n = _boundary_node_id.find(node);

  // node not in the data structure
  if (n == _boundary_node_id.end())
    return invalid_id;

  return n->second;
}

short int BoundaryInfo::boundary_id(const Elem* const elem,
				    const unsigned short int side) const
{
  libmesh_assert (elem != NULL);

  // Only level-0 elements store BCs.  If this is not a level-0
  // element get its level-0 parent and infer the BCs.
  const Elem*  searched_elem = elem;
  if (elem->level() != 0)
    searched_elem = elem->top_parent ();

  std::pair<std::multimap<const Elem*,
                          std::pair<unsigned short int, short int> >::const_iterator,
            std::multimap<const Elem*,
                          std::pair<unsigned short int, short int> >::const_iterator >
    e = _boundary_side_id.equal_range(searched_elem);

  // elem not in the data structure
  if (e.first == e.second)
    return invalid_id;

  // elem is there, maybe multiple occurances
  while (e.first != e.second)
    {
      // if this is true we found the requested side
      // of the element and want to return the id
      if (e.first->second.first == side)
	return e.first->second.second;

      ++e.first;
    }

  // if we get here, we found elem in the data structure but not
  // the requested side, so return the default value
  return invalid_id;
}

unsigned int BoundaryInfo::side_with_boundary_id(const Elem* const elem,
                                                 const unsigned short int boundary_id) const
{
  const Elem* searched_elem = elem;
  if (elem->level() != 0)
    searched_elem = elem->top_parent();

  std::pair<std::multimap<const Elem*,
                          std::pair<unsigned short int, short int> >::const_iterator,
            std::multimap<const Elem*,
                          std::pair<unsigned short int, short int> >::const_iterator >
    e = _boundary_side_id.equal_range(searched_elem);

  // elem not in the data structure
  if (e.first == e.second)
    return libMesh::invalid_uint;

  // elem is there, maybe multiple occurances
  while (e.first != e.second)
    {
      // if this is true we found the requested boundary_id
      // of the element and want to return the side
      if (e.first->second.second == boundary_id)
	return e.first->second.first;

      ++e.first;
    }

  // if we get here, we found elem in the data structure but not
  // the requested boundary id, so return the default value
  return libMesh::invalid_uint;
}

unsigned int BoundaryInfo::n_boundary_conds () const
{
  // in serial we know the number of bcs from the
  // size of the container
  if (_mesh.is_serial())
    return _boundary_side_id.size();

  // in parallel we need to sum the number of local bcs
  parallel_only();

  unsigned int nbcs=0;

  std::multimap<const Elem*,
                std::pair<unsigned short int,
                          short int> >::const_iterator pos;

  for (pos=_boundary_side_id.begin(); pos != _boundary_side_id.end(); ++pos)
    if (pos->first->processor_id() == libMesh::processor_id())
      nbcs++;

  Parallel::sum (nbcs);

  return nbcs;
}

void BoundaryInfo::build_node_list (std::vector<unsigned int>& nl,
				    std::vector<short int>&    il) const
{
  // Reserve the size, then use push_back
  nl.reserve (_boundary_node_id.size());
  il.reserve (_boundary_node_id.size());

  std::map<const Node*, short int>::const_iterator pos
    = _boundary_node_id.begin();

  for (; pos != _boundary_node_id.end(); ++pos)
    {
      nl.push_back (pos->first->id());
      il.push_back (pos->second);
    }
}

void BoundaryInfo::build_side_list (std::vector<unsigned int>&       el,
				    std::vector<unsigned short int>& sl,
				    std::vector<short int>&          il) const
{
  // Reserve the size, then use push_back
  el.reserve (_boundary_side_id.size());
  sl.reserve (_boundary_side_id.size());
  il.reserve (_boundary_side_id.size());

  std::multimap<const Elem*,
                std::pair<unsigned short int,
                          short int> >::const_iterator pos;

  for (pos=_boundary_side_id.begin(); pos != _boundary_side_id.end();
       ++pos)
    {
      el.push_back (pos->first->id());
      sl.push_back (pos->second.first);
      il.push_back (pos->second.second);
    }
}

void BoundaryInfo::print_info() const
{
  // Print out the nodal BCs
  if (!_boundary_node_id.empty())
    {
      std::cout << "Nodal Boundary conditions:" << std::endl
		<< "--------------------------" << std::endl
		<< "  (Node No., ID)               " << std::endl;

//       std::for_each(_boundary_node_id.begin(),
// 		    _boundary_node_id.end(),
// 		    PrintNodeInfo());

      std::map<const Node*, short int>::const_iterator it        = _boundary_node_id.begin();
      const std::map<const Node*, short int>::const_iterator end = _boundary_node_id.end();

      for (; it != end; ++it)
	std::cout << "  (" << (*it).first->id()
		  << ", "  << (*it).second
		  << ")"  << std::endl;
    }

  // Print out the element BCs
  if (!_boundary_side_id.empty())
    {
      std::cout << std::endl
		<< "Side Boundary conditions:" << std::endl
		<< "-------------------------" << std::endl
		<< "  (Elem No., Side No., ID)      " << std::endl;

//       std::for_each(_boundary_side_id.begin(),
// 		    _boundary_side_id.end(),
//   		    PrintSideInfo());

      std::multimap<const Elem*,
	std::pair<unsigned short int, short int> >::const_iterator it = _boundary_side_id.begin();
      const std::multimap<const Elem*,
	std::pair<unsigned short int, short int> >::const_iterator end = _boundary_side_id.end();

     for (; it != end; ++it)
       std::cout << "  (" << (*it).first->id()
		 << ", "  << (*it).second.first
		 << ", "  << (*it).second.second
		 << ")"   << std::endl;
    }
}
<commit_msg>Removed unused local variable which was a map<int,int> called new_node_numbers from the sync().  Not sure why it was there, probably just an oversight.<commit_after>// $Id$

// The libMesh Finite Element Library.
// Copyright (C) 2002-2008 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes

// Local includes
#include "libmesh_config.h"
#include "boundary_info.h"
#include "boundary_mesh.h"
#include "elem.h"
#include "mesh_data.h"
#include "parallel.h"

//------------------------------------------------------
// BoundaryInfo static member initializations
const short int BoundaryInfo::invalid_id = -1234;

//------------------------------------------------------
// BoundaryInfo functions
BoundaryInfo::BoundaryInfo(const MeshBase& m) :
  _mesh (m)
{
}

BoundaryInfo::~BoundaryInfo()
{
  this->clear();
}

void BoundaryInfo::clear()
{
  _boundary_node_id.clear();
  _boundary_side_id.clear();
  _boundary_ids.clear();
}

void BoundaryInfo::sync(BoundaryMesh& boundary_mesh,
			MeshData*     boundary_mesh_data,
			MeshData*     this_mesh_data)
{
  boundary_mesh.clear();

  /**
   * Re-create the boundary mesh.
   */
  boundary_mesh.set_n_subdomains() = this->n_boundary_ids();

  // Add sides to the structure.
  std::map<short int, unsigned int> id_map;

  // Original Code
  //     unsigned int cnt = 0;
  //     for (std::set<short int>::iterator pos = boundary_ids.begin();
  // 	 pos != boundary_ids.end(); ++pos)
  //       id_map[*pos] = cnt++;

  //     id_map[invalid_id] = cnt;

  // New code
  // Here we need to use iota() once it is in the
  // Utility namespace.
  std::for_each(_boundary_ids.begin(),
		_boundary_ids.end(),
		Fill(id_map));

  boundary_mesh.set_n_subdomains() = id_map.size();

  // Make individual copies of all the nodes in the current mesh
  // and add them to the boundary mesh.  Yes, this is overkill because
  // all of the current mesh nodes will not end up in the the boundary
  // mesh.  These nodes can be trimmed later via a call to prepare_for_use().
  {
    libmesh_assert (boundary_mesh.n_nodes() == 0);
    boundary_mesh.reserve_nodes(_mesh.n_nodes());

    MeshBase::const_node_iterator it  = _mesh.nodes_begin();
    MeshBase::const_node_iterator end = _mesh.nodes_end();

    for(; it != end; ++it)
      {
	const Node* node = *it;
	boundary_mesh.add_point(*node); // calls Node::build(Point, id)
      }
  }

  // Add additional sides that aren't flagged with boundary conditions
  MeshBase::const_element_iterator       el     = _mesh.active_elements_begin();
  const MeshBase::const_element_iterator end_el = _mesh.active_elements_end();

  for ( ; el != end_el; ++el)
    {
      const Elem* elem = *el;

      for (unsigned int s=0; s<elem->n_sides(); s++)
	if (elem->neighbor(s) == NULL) // on the boundary
	  {

	    // Build the side - do not use a "proxy" element here:
	    // This will be going into the BoundaryMesh and needs to
	    // stand on its own.
	    AutoPtr<Elem> side (elem->build_side(s, false));

	    // Get the top-level parent for this element
	    const Elem* top_parent = elem->top_parent();

	    // A convenient typedef
	    typedef
	      std::multimap<const Elem*, std::pair<unsigned short int, short int> >::const_iterator
	      Iter;

	    // Find the right id number for that side
	    std::pair<Iter, Iter> pos = _boundary_side_id.equal_range(top_parent);

	    while (pos.first != pos.second)
	      {
		if (pos.first->second.first == s) // already flagged with a boundary condition
		  {
		    side->subdomain_id() =
		      id_map[pos.first->second.second];

		    side->processor_id() =
		      side->subdomain_id();
		    break;
		  }

		++pos.first;
	      }

	    // either the element wasn't found or side s
	    // doesn't have a boundary condition
	    if (pos.first == pos.second)
	      {
		side->subdomain_id() = id_map[invalid_id];
	      }

	    // Add the side
	    Elem* new_elem = boundary_mesh.add_elem(side.release());

	    // This side's Node pointers still point to the nodes of the  original mesh.
	    // We need to re-point them to the boundary mesh's nodes!  Since we copied *ALL* of
	    // the original mesh's nodes over, we should be guaranteed to have the same ordering.
	    for (unsigned int nn=0; nn<new_elem->n_nodes(); ++nn)
	      {
		// Get the correct node pointer, based on the id()
		Node* new_node = boundary_mesh.node_ptr(new_elem->node(nn));

		// sanity check: be sure that the new Nodes global id really matches
		libmesh_assert (new_node->id() == new_elem->node(nn));

		// Assign the new node pointer
		new_elem->set_node(nn) = new_node;
	      }
	  }
    } // end loop over active elements

  // When desired, copy the MeshData
  // to the boundary_mesh
  if ((boundary_mesh_data != NULL) && (this_mesh_data != NULL))
    boundary_mesh_data->assign(*this_mesh_data);

  // Trim any un-used nodes from the Mesh
  boundary_mesh.prepare_for_use();
}

void BoundaryInfo::add_node(const unsigned int node,
			    const short int id)
{
  this->add_node (_mesh.node_ptr(node), id);
}

void BoundaryInfo::add_node(const Node* node,
			    const short int id)
{
  if (id == invalid_id)
    {
      std::cerr << "ERROR: You may not set a boundary ID of "
		<< invalid_id << std::endl
		<< " That is reserved for internal use.\n"
		<< std::endl;

      libmesh_error();
    }

  _boundary_node_id[node] = id;
  _boundary_ids.insert(id);
}

void BoundaryInfo::add_side(const unsigned int e,
			    const unsigned short int side,
			    const short int id)
{
  this->add_side (_mesh.elem(e), side, id);
}

void BoundaryInfo::add_side(const Elem* elem,
			    const unsigned short int side,
			    const short int id)
{
  libmesh_assert (elem != NULL);

  // Only add BCs for level-0 elements.
  libmesh_assert (elem->level() == 0);

  if (id == invalid_id)
    {
      std::cerr << "ERROR: You may not set a boundary ID of "
		<< invalid_id << std::endl
		<< " That is reserved for internal use.\n"
		<< std::endl;

      libmesh_error();
    }

  std::pair<unsigned short int, short int> p(side,id);
  std::pair<const Elem*, std::pair<unsigned short int, short int> >
    kv (elem, p);

  _boundary_side_id.insert(kv);
  _boundary_ids.insert(id);
}

short int BoundaryInfo::boundary_id(const Node* node) const
{
  std::map<const Node*, short int>::const_iterator
    n = _boundary_node_id.find(node);

  // node not in the data structure
  if (n == _boundary_node_id.end())
    return invalid_id;

  return n->second;
}

short int BoundaryInfo::boundary_id(const Elem* const elem,
				    const unsigned short int side) const
{
  libmesh_assert (elem != NULL);

  // Only level-0 elements store BCs.  If this is not a level-0
  // element get its level-0 parent and infer the BCs.
  const Elem*  searched_elem = elem;
  if (elem->level() != 0)
    searched_elem = elem->top_parent ();

  std::pair<std::multimap<const Elem*,
                          std::pair<unsigned short int, short int> >::const_iterator,
            std::multimap<const Elem*,
                          std::pair<unsigned short int, short int> >::const_iterator >
    e = _boundary_side_id.equal_range(searched_elem);

  // elem not in the data structure
  if (e.first == e.second)
    return invalid_id;

  // elem is there, maybe multiple occurances
  while (e.first != e.second)
    {
      // if this is true we found the requested side
      // of the element and want to return the id
      if (e.first->second.first == side)
	return e.first->second.second;

      ++e.first;
    }

  // if we get here, we found elem in the data structure but not
  // the requested side, so return the default value
  return invalid_id;
}

unsigned int BoundaryInfo::side_with_boundary_id(const Elem* const elem,
                                                 const unsigned short int boundary_id) const
{
  const Elem* searched_elem = elem;
  if (elem->level() != 0)
    searched_elem = elem->top_parent();

  std::pair<std::multimap<const Elem*,
                          std::pair<unsigned short int, short int> >::const_iterator,
            std::multimap<const Elem*,
                          std::pair<unsigned short int, short int> >::const_iterator >
    e = _boundary_side_id.equal_range(searched_elem);

  // elem not in the data structure
  if (e.first == e.second)
    return libMesh::invalid_uint;

  // elem is there, maybe multiple occurances
  while (e.first != e.second)
    {
      // if this is true we found the requested boundary_id
      // of the element and want to return the side
      if (e.first->second.second == boundary_id)
	return e.first->second.first;

      ++e.first;
    }

  // if we get here, we found elem in the data structure but not
  // the requested boundary id, so return the default value
  return libMesh::invalid_uint;
}

unsigned int BoundaryInfo::n_boundary_conds () const
{
  // in serial we know the number of bcs from the
  // size of the container
  if (_mesh.is_serial())
    return _boundary_side_id.size();

  // in parallel we need to sum the number of local bcs
  parallel_only();

  unsigned int nbcs=0;

  std::multimap<const Elem*,
                std::pair<unsigned short int,
                          short int> >::const_iterator pos;

  for (pos=_boundary_side_id.begin(); pos != _boundary_side_id.end(); ++pos)
    if (pos->first->processor_id() == libMesh::processor_id())
      nbcs++;

  Parallel::sum (nbcs);

  return nbcs;
}

void BoundaryInfo::build_node_list (std::vector<unsigned int>& nl,
				    std::vector<short int>&    il) const
{
  // Reserve the size, then use push_back
  nl.reserve (_boundary_node_id.size());
  il.reserve (_boundary_node_id.size());

  std::map<const Node*, short int>::const_iterator pos
    = _boundary_node_id.begin();

  for (; pos != _boundary_node_id.end(); ++pos)
    {
      nl.push_back (pos->first->id());
      il.push_back (pos->second);
    }
}

void BoundaryInfo::build_side_list (std::vector<unsigned int>&       el,
				    std::vector<unsigned short int>& sl,
				    std::vector<short int>&          il) const
{
  // Reserve the size, then use push_back
  el.reserve (_boundary_side_id.size());
  sl.reserve (_boundary_side_id.size());
  il.reserve (_boundary_side_id.size());

  std::multimap<const Elem*,
                std::pair<unsigned short int,
                          short int> >::const_iterator pos;

  for (pos=_boundary_side_id.begin(); pos != _boundary_side_id.end();
       ++pos)
    {
      el.push_back (pos->first->id());
      sl.push_back (pos->second.first);
      il.push_back (pos->second.second);
    }
}

void BoundaryInfo::print_info() const
{
  // Print out the nodal BCs
  if (!_boundary_node_id.empty())
    {
      std::cout << "Nodal Boundary conditions:" << std::endl
		<< "--------------------------" << std::endl
		<< "  (Node No., ID)               " << std::endl;

//       std::for_each(_boundary_node_id.begin(),
// 		    _boundary_node_id.end(),
// 		    PrintNodeInfo());

      std::map<const Node*, short int>::const_iterator it        = _boundary_node_id.begin();
      const std::map<const Node*, short int>::const_iterator end = _boundary_node_id.end();

      for (; it != end; ++it)
	std::cout << "  (" << (*it).first->id()
		  << ", "  << (*it).second
		  << ")"  << std::endl;
    }

  // Print out the element BCs
  if (!_boundary_side_id.empty())
    {
      std::cout << std::endl
		<< "Side Boundary conditions:" << std::endl
		<< "-------------------------" << std::endl
		<< "  (Elem No., Side No., ID)      " << std::endl;

//       std::for_each(_boundary_side_id.begin(),
// 		    _boundary_side_id.end(),
//   		    PrintSideInfo());

      std::multimap<const Elem*,
	std::pair<unsigned short int, short int> >::const_iterator it = _boundary_side_id.begin();
      const std::multimap<const Elem*,
	std::pair<unsigned short int, short int> >::const_iterator end = _boundary_side_id.end();

     for (; it != end; ++it)
       std::cout << "  (" << (*it).first->id()
		 << ", "  << (*it).second.first
		 << ", "  << (*it).second.second
		 << ")"   << std::endl;
    }
}
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <qi/anyobject.hpp>
#include "transportserver.hpp"
#include <qi/messaging/serviceinfo.hpp>
#include <qi/type/objecttypebuilder.hpp>
#include "objectregistrar.hpp"
#include "serverresult.hpp"
#include <qi/os.hpp>
#include <boost/thread/mutex.hpp>
#include "servicedirectoryclient.hpp"

qiLogCategory("qimessaging.server");

namespace qi {

  //Server
  Server::Server()
    : qi::Trackable<Server>(this)
    ,_boundObjectsMutex()
    , _server()
    , _dying(false)
    , _defaultCallType(qi::MetaCallType_Queued)
  {
    _server.newConnection.connect(&Server::onTransportServerNewConnection, this, _1, true);
  }

  Server::~Server()
  {
    //we can call reset on server and socket they are only owned by us.
    //when it's close it's close
    _server.newConnection.disconnectAll();
    close();
    destroy();
  }

  bool Server::addObject(unsigned int id, qi::AnyObject obj)
  {
    if (!obj)
      return false;
    BoundAnyObject bop = makeServiceBoundAnyObject(id, obj, _defaultCallType);
    return addObject(id, bop);
  }

  bool Server::addObject(unsigned int id, qi::BoundAnyObject obj)
  {
    if (!obj)
      return false;
    //register into _boundObjects
    {
      boost::mutex::scoped_lock sl(_boundObjectsMutex);
      BoundAnyObjectMap::iterator it;
      it = _boundObjects.find(id);
      if (it != _boundObjects.end()) {
        return false;
      }
      _boundObjects[id] = obj;
      return true;
    }
  }

  bool Server::removeObject(unsigned int idx)
  {
    {
      boost::mutex::scoped_lock sl(_boundObjectsMutex);
      BoundAnyObjectMap::iterator it;
      it = _boundObjects.find(idx);
      if (it == _boundObjects.end()) {
        return false;
      }
      _boundObjects.erase(idx);
    }
    return true;
  }

  void Server::onTransportServerNewConnection(TransportSocketPtr socket, bool startReading)
  {
    boost::recursive_mutex::scoped_lock sl(_socketsMutex);
    if (!socket)
      return;
    if (_dying)
    {
      qiLogDebug() << "Incoming connectiong while closing, dropping...";
      socket->disconnect().async();
      return;
    }
    _sockets.push_back(socket);
    socket->disconnected.connect(&Server::onSocketDisconnected, this, socket, _1);
    socket->messageReady.connect(&Server::onMessageReady, this, _1, socket);
    if (startReading)
      socket->startReading();
  }

  void Server::onMessageReady(const qi::Message &msg, TransportSocketPtr socket) {
    qi::BoundAnyObject obj;
    // qiLogDebug() << "Server Recv (" << msg.type() << "):" << msg.address();
    {
      boost::mutex::scoped_lock sl(_boundObjectsMutex);
      BoundAnyObjectMap::iterator it;

      it = _boundObjects.find(msg.service());
      if (it == _boundObjects.end())
      {
        // The message could be addressed to a bound object, inside a
        // remoteobject host, or to a remoteobject, using the same socket.
        qiLogVerbose() << "No service for " << msg.address();
        if (msg.object() > Message::GenericObject_Main
          || msg.type() == Message::Type_Reply
          || msg.type() == Message::Type_Event
          || msg.type() == Message::Type_Error)
          return;
        // ... but only if the object id is >main
        qi::Message       retval(Message::Type_Error, msg.address());
        std::stringstream ss;
        ss << "can't find service, address: " << msg.address();
        retval.setError(ss.str());
        socket->send(retval);
        qiLogError() << "Can't find service: " << msg.service() << " on " << msg.address();
        return;
      }
      obj            = it->second;
    }
    // We were called from the thread pool: synchronous call is ok
    //qi::getEventLoop()->post(boost::bind<void>(&BoundObject::onMessage, obj, msg, socket));
    obj->onMessage(msg, socket);
  }

  void Server::close()
  {
    {
      boost::mutex::scoped_lock l(_stateMutex);

      if (_dying)
      {
        return;
      }

      _dying = true;
    }

    qiLogVerbose() << "Closing server...";
    {
      std::list<TransportSocketPtr> socketsCopy;
      {
        boost::recursive_mutex::scoped_lock sl(_socketsMutex);
        std::swap(_sockets, socketsCopy);
      }
      std::list<TransportSocketPtr>::iterator it;
      //TODO move that logic into TransportServer
      for (it = socketsCopy.begin(); it != socketsCopy.end(); ++it) {
        (*it)->connected.disconnectAll();
        (*it)->disconnected.disconnectAll();
        (*it)->messageReady.disconnectAll();
        (*it)->disconnect();
      }
    }
    _server.close();
  }

  qi::Future<void> Server::listen(const qi::Url &address)
  {
    // Assume this means we are back on-line.
    _dying = false;
    return _server.listen(address);
  }

  bool Server::setIdentity(const std::string& key, const std::string& crt)
  {
    return _server.setIdentity(key, crt);
  }

  void Server::onSocketDisconnected(TransportSocketPtr socket, std::string error)
  {
    TransportSocketPtr match;
    {
      boost::mutex::scoped_lock l(_stateMutex);
      if (_dying)
      {
        return;
      }

      BoundAnyObjectMap::iterator it;
      {
        boost::mutex::scoped_lock sl(_boundObjectsMutex);
        for (it = _boundObjects.begin(); it != _boundObjects.end(); ++it) {
          BoundAnyObject o = it->second;
          try
          {
            o->onSocketDisconnected(socket, error);
          }
          catch (const std::runtime_error& e)
          {
            qiLogError() << e.what();
          }
        }
      }

      {
        {
          boost::recursive_mutex::scoped_lock sl(_socketsMutex);
          std::list<TransportSocketPtr>::iterator it = std::find(_sockets.begin(), _sockets.end(), socket);
          if (it != _sockets.end())
          {
            match = *it;
            _sockets.erase(it);
          }
        }
      }
    }
    if (match)
    {
      match->connected.disconnectAll();
      match->disconnected.disconnectAll();
      match->messageReady.disconnectAll();
    }
  }

  qi::UrlVector Server::endpoints() const {
    return _server.endpoints();
  }

  void Server::open()
  {
    _dying = false;
  }

}
<commit_msg>Fixes redmine #22839<commit_after>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <qi/anyobject.hpp>
#include "transportserver.hpp"
#include <qi/messaging/serviceinfo.hpp>
#include <qi/type/objecttypebuilder.hpp>
#include "objectregistrar.hpp"
#include "serverresult.hpp"
#include <qi/os.hpp>
#include <boost/thread/mutex.hpp>
#include "servicedirectoryclient.hpp"

qiLogCategory("qimessaging.server");

namespace qi {

  //Server
  Server::Server()
    : qi::Trackable<Server>(this)
    ,_boundObjectsMutex()
    , _server()
    , _dying(false)
    , _defaultCallType(qi::MetaCallType_Queued)
  {
    _server.newConnection.connect(&Server::onTransportServerNewConnection, this, _1, true);
  }

  Server::~Server()
  {
    //we can call reset on server and socket they are only owned by us.
    //when it's close it's close
    _server.newConnection.disconnectAll();
    close();
    destroy();
  }

  bool Server::addObject(unsigned int id, qi::AnyObject obj)
  {
    if (!obj)
      return false;
    BoundAnyObject bop = makeServiceBoundAnyObject(id, obj, _defaultCallType);
    return addObject(id, bop);
  }

  bool Server::addObject(unsigned int id, qi::BoundAnyObject obj)
  {
    if (!obj)
      return false;
    //register into _boundObjects
    {
      boost::mutex::scoped_lock sl(_boundObjectsMutex);
      BoundAnyObjectMap::iterator it;
      it = _boundObjects.find(id);
      if (it != _boundObjects.end()) {
        return false;
      }
      _boundObjects[id] = obj;
      return true;
    }
  }

  bool Server::removeObject(unsigned int idx)
  {
    {
      boost::mutex::scoped_lock sl(_boundObjectsMutex);
      BoundAnyObjectMap::iterator it;
      it = _boundObjects.find(idx);
      if (it == _boundObjects.end()) {
        return false;
      }
      _boundObjects.erase(idx);
    }
    return true;
  }

  void Server::onTransportServerNewConnection(TransportSocketPtr socket, bool startReading)
  {
    boost::recursive_mutex::scoped_lock sl(_socketsMutex);
    if (!socket)
      return;
    if (_dying)
    {
      qiLogDebug() << "Incoming connectiong while closing, dropping...";
      socket->disconnect().async();
      return;
    }
    _sockets.push_back(socket);
    socket->disconnected.connect(&Server::onSocketDisconnected, this, socket, _1);
    socket->messageReady.connect(&Server::onMessageReady, this, _1, socket);
    if (startReading)
      socket->startReading();
  }

  void Server::onMessageReady(const qi::Message &msg, TransportSocketPtr socket) {
    qi::BoundAnyObject obj;
    // qiLogDebug() << "Server Recv (" << msg.type() << "):" << msg.address();
    {
      boost::mutex::scoped_lock sl(_boundObjectsMutex);
      BoundAnyObjectMap::iterator it;

      it = _boundObjects.find(msg.service());
      if (it == _boundObjects.end())
      {
        // The message could be addressed to a bound object, inside a
        // remoteobject host, or to a remoteobject, using the same socket.
        qiLogVerbose() << "No service for " << msg.address();
        if (msg.object() > Message::GenericObject_Main
          || msg.type() == Message::Type_Reply
          || msg.type() == Message::Type_Event
          || msg.type() == Message::Type_Error)
          return;
        // ... but only if the object id is >main
        qi::Message       retval(Message::Type_Error, msg.address());
        std::stringstream ss;
        ss << "can't find service, address: " << msg.address();
        retval.setError(ss.str());
        socket->send(retval);
        qiLogError() << "Can't find service: " << msg.service() << " on " << msg.address();
        return;
      }
      obj            = it->second;
    }
    // We were called from the thread pool: synchronous call is ok
    //qi::getEventLoop()->post(boost::bind<void>(&BoundObject::onMessage, obj, msg, socket));
    obj->onMessage(msg, socket);
  }

  void Server::close()
  {
    {
      boost::mutex::scoped_lock l(_stateMutex);

      if (_dying)
      {
        return;
      }

      _dying = true;
    }

    qiLogVerbose() << "Closing server...";
    {
      std::list<TransportSocketPtr> socketsCopy;
      {
        boost::recursive_mutex::scoped_lock sl(_socketsMutex);
        std::swap(_sockets, socketsCopy);
      }
      std::list<TransportSocketPtr>::iterator it;
      //TODO move that logic into TransportServer
      for (it = socketsCopy.begin(); it != socketsCopy.end(); ++it) {
        (*it)->connected.disconnectAll();
        (*it)->disconnected.disconnectAll();
        (*it)->messageReady.disconnectAll();
        (*it)->disconnect();
      }
    }
    _server.close();
  }

  qi::Future<void> Server::listen(const qi::Url &address)
  {
    // Assume this means we are back on-line.
    _dying = false;
    return _server.listen(address);
  }

  bool Server::setIdentity(const std::string& key, const std::string& crt)
  {
    return _server.setIdentity(key, crt);
  }

  void Server::onSocketDisconnected(TransportSocketPtr socket, std::string error)
  {
    {
      boost::mutex::scoped_lock l(_stateMutex);
      if (_dying)
      {
        return;
      }

      BoundAnyObjectMap::iterator it;
      {
        boost::mutex::scoped_lock sl(_boundObjectsMutex);
        for (it = _boundObjects.begin(); it != _boundObjects.end(); ++it) {
          BoundAnyObject o = it->second;
          try
          {
            o->onSocketDisconnected(socket, error);
          }
          catch (const std::runtime_error& e)
          {
            qiLogError() << e.what();
          }
        }
      }

      {
        {
          boost::recursive_mutex::scoped_lock sl(_socketsMutex);
          std::list<TransportSocketPtr>::iterator it = std::find(_sockets.begin(), _sockets.end(), socket);
          if (it != _sockets.end())
            _sockets.erase(it);
        }
      }
    }
  }

  qi::UrlVector Server::endpoints() const {
    return _server.endpoints();
  }

  void Server::open()
  {
    _dying = false;
  }

}
<|endoftext|>


<commit_before>#include "gcoder_gantry.h"
#include "gcoder.h"
#include <cmath>
#include <iostream>
#include <sstream>

namespace mgl {

using std::ostream;
using std::endl;
using std::string;
using std::stringstream;
using libthing::LineSegment2;
using libthing::Vector2;

Gantry::Gantry(const GantryConfig& gCfg) : gantryCfg(gCfg) {
	set_current_extruder_index('A');
	set_extruding(false);
	init_to_start();
}

Scalar Gantry::get_x() const {
	return x;
}

Scalar Gantry::get_y() const {
	return y;
}

Scalar Gantry::get_z() const {
	return z;
}

Scalar Gantry::get_a() const {
	return a;
}

Scalar Gantry::get_b() const {
	return b;
}

Scalar Gantry::get_feed() const {
	return feed;
}

bool Gantry::get_extruding() const {
	return extruding;
}

unsigned char Gantry::get_current_extruder_code() const {
	return ab;
}

void Gantry::set_x(Scalar nx) {
	x = nx;
}

void Gantry::set_y(Scalar ny) {
	y = ny;
}

void Gantry::set_z(Scalar nz) {
	z = nz;
}

void Gantry::set_a(Scalar na) {
	a = na;
}

void Gantry::set_b(Scalar nb) {
	b = nb;
}

void Gantry::set_feed(Scalar nfeed) {
	feed = nfeed;
}

void Gantry::set_extruding(bool nextruding) {
	extruding = nextruding;
}

void Gantry::set_current_extruder_index(unsigned char nab) {
	ab = nab;
}

void Gantry::init_to_start() {
	set_x(gantryCfg.get_start_x());
	set_y(gantryCfg.get_start_y());
	set_z(gantryCfg.get_start_z());
	set_a(gantryCfg.get_start_a());
	set_b(gantryCfg.get_start_b());
	set_feed(gantryCfg.get_start_feed());
}

/// get axis value of the current extruder in(mm)
/// (aka mm of feedstock since the last reset this print)

Scalar Gantry::getCurrentE() const {
	switch (get_current_extruder_code()) {
	case 'A':
		return get_a();
		break;
	case 'B':
		return get_b();
		break;
	default:
	{
		string msg("Illegal extruder index ");
		msg.push_back(get_current_extruder_code());
		throw GcoderException(msg.c_str());
		return 0;
		break;
	}
	}
}

void Gantry::setCurrentE(Scalar e) {
	switch (get_current_extruder_code()) {
	case 'A':
		set_a(e);
		break;
	case 'B':
		set_b(e);
		break;
	default:
	{
		string msg("Illegal extruder index ");
		msg.push_back(get_current_extruder_code());
		throw GcoderException(msg.c_str());
		break;
	}
	}
}

void Gantry::writeSwitchExtruder(ostream& ss, Extruder &extruder) {
	ss << "( extruder " << extruder.id << " )" << endl;
	ss << "( GSWITCH T" << extruder.id << " )" << endl;
	ss << "( TODO: add offset management to Gantry )" << endl;
	ab = extruder.code;
	ss << endl;
}

Scalar Gantry::volumetricE(const Extruder &extruder,
		const Extrusion &extrusion,
		Scalar vx, Scalar vy, Scalar /*vz*/,
		Scalar h, Scalar w) const {
	//There isn't yet a LineSegment3, so for now I'm assuming that only 2d
	//segments get extruded
	LineSegment2 seg(Vector2(get_x(), get_y()), Vector2(vx, vy));
	Scalar seg_volume = gantryCfg.segmentVolume(extruder, extrusion, seg, h, w);

	Scalar feed_cross_area = extruder.feedCrossSectionArea();

	Scalar feed_len = seg_volume / feed_cross_area;

	return feed_len + getCurrentE();
}

/*if extruder and extrusion are null we don't extrude*/
void Gantry::g1(std::ostream &ss,
		const Extruder *extruder, const Extrusion *extrusion,
		Scalar gx, Scalar gy, Scalar gz, Scalar gfeed,
		Scalar h, Scalar w,
		const char *comment = NULL) {

	bool doX = true;
	bool doY = true;
	bool doZ = true;
	bool doFeed = true;
	bool doE = false;
	Scalar me = getCurrentE();

	PointType relativeVector(gx - get_x(), gy - get_y());

	if (!libthing::tequals(get_x(), gx, SAMESAME_TOL)) {
		doX = true;
	}
	if (!libthing::tequals(get_y(), gy, SAMESAME_TOL)) {
		doY = true;
	}
	if (!libthing::tequals(get_z(), gz, SAMESAME_TOL)) {
		doZ = true;
	}
	if (!libthing::tequals(get_feed(), gfeed, SAMESAME_TOL)) {
		doFeed = true;
	}
	if (get_extruding() && extruder && extrusion &&
			extruder->isVolumetric()) {
		doE = true;
		me = volumetricE(*extruder, *extrusion, gx, gy, gz, h, w);
		if(libthing::tequals(me, getCurrentE(), 0.0) ||
				relativeVector.magnitude() <= gantryCfg.get_coarseness())
			return;
	}
	g1Motion(ss, gx, gy, gz, me, gfeed, h, w, comment,
			doX, doY, doZ, doE, doFeed);
}

void Gantry::squirt(std::ostream &ss, const Vector2 &lineStart,
		const Extruder &extruder, const Extrusion &extrusion) {
	if(get_extruding())
		return;
	if (extruder.isVolumetric()) {
		g1Motion(ss, get_x(), get_y(), get_z(),
				getCurrentE() + extruder.retractDistance
				+ extruder.restartExtraDistance,
                extruder.retractRate * gantryCfg.get_scaling_factor(),
				FLUID_H, FLUID_W,
				"squirt", false, false, false, true, true); //only E and F
	} else {
		//we don't support RPM anymore
	}

	set_extruding(true);
}

void Gantry::snort(std::ostream &ss, const Vector2 &lineEnd,
		const Extruder &extruder, const Extrusion &extrusion) {
	if(!get_extruding())
		return;
	if (extruder.isVolumetric()) {
		g1Motion(ss, get_x(), get_y(), get_z(),
				getCurrentE() - extruder.retractDistance,
				extruder.retractRate * gantryCfg.get_scaling_factor(),
                FLUID_H, FLUID_W, "snort",
				false, false, false, true, true); //only E and F
	} else {
		//we don't support RPM anymore
	}

	set_extruding(false);
}

void Gantry::g1Motion(std::ostream &ss, Scalar mx, Scalar my, Scalar mz,
		Scalar me, Scalar mfeed, Scalar /*h*/, Scalar /*w*/,
		const char *g1Comment, bool doX,
		bool doY, bool doZ, bool doE, bool doFeed) {

	// not do something is not an option .. under certain conditions
#ifdef STRONG_CHECKING
	if (!(doX || doY || doZ || doFeed)) {
		stringstream ss;
		ss << "G1 without moving where x=" << x << ", y=" << y << ", z=" << z << ", feed=" << feed;
		GcoderException mixup(ss.str().c_str());
		throw mixup;
	}
#endif

	// our moto: don't be bad!
	bool bad = false;
	if (fabs(mx) > MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM) bad = true;
	if (fabs(my) > MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM) bad = true;
	if (fabs(mz) > MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM) bad = true;
	if (mfeed <= 0 || mfeed > 100000) bad = true;

	if (bad) {
		stringstream ss;
		ss << "Illegal G1 move where x=" << mx << ", y=" << my << ", z=" << mz << ", feed=" << mfeed;
		GcoderException mixup(ss.str().c_str());
		throw mixup;
	}

	unsigned char ss_axis =
			(gantryCfg.get_use_e_axis() ? 'E' :
			get_current_extruder_code());

	ss << "G1";
	if (doX) ss << " X" << mx;
	if (doY) ss << " Y" << my;
	if (doZ) ss << " Z" << mz;
	if (doFeed) ss << " F" << mfeed;
	if (doE) ss << " " << ss_axis << me;
	if (g1Comment) ss << " (" << g1Comment << ")";
	ss << endl;

	// if(feed >= 5000) assert(0);

	// update state machine
	if (doX) set_x(mx);
	if (doY) set_y(my);
	if (doZ) set_z(mz);
	if (doFeed) set_feed(mfeed);
	if (doE) setCurrentE(me);
}

GantryConfig::GantryConfig() {
	set_start_x(MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM);
	set_start_y(MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM);
	set_start_z(MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM);
	set_start_a(0);
	set_start_b(0);
	set_start_feed(0);
}

Scalar GantryConfig::get_start_x() const {
	return sx;
}

Scalar GantryConfig::get_start_y() const {
	return sy;
}

Scalar GantryConfig::get_start_z() const {
	return sz;
}

Scalar GantryConfig::get_start_a() const {
	return sa;
}

Scalar GantryConfig::get_start_b() const {
	return sb;
}

Scalar GantryConfig::get_start_feed() const {
	return sfeed;
}

void GantryConfig::set_start_x(Scalar nx) {
	sx = nx;
}

void GantryConfig::set_start_y(Scalar ny) {
	sy = ny;
}

void GantryConfig::set_start_z(Scalar nz) {
	sz = nz;
}

void GantryConfig::set_start_a(Scalar na) {
	sa = na;
}

void GantryConfig::set_start_b(Scalar nb) {
	sb = nb;
}

void GantryConfig::set_start_feed(Scalar nfeed) {
	sfeed = nfeed;
}

Scalar GantryConfig::get_rapid_move_feed_rate_xy() const {
	return rapidMoveFeedRateXY;
}

Scalar GantryConfig::get_rapid_move_feed_rate_z() const {
	return rapidMoveFeedRateZ;
}

bool GantryConfig::get_use_e_axis() const {
	return useEaxis;
}

Scalar GantryConfig::get_layer_h() const {
	return layerH;
}

Scalar GantryConfig::get_scaling_factor() const {
	return scalingFactor;
}

Scalar GantryConfig::get_coarseness() const {
	return coarseness;
}

Scalar GantryConfig::segmentVolume(const Extruder &, // extruder,
		const Extrusion &extrusion,
		LineSegment2 &segment, Scalar h, Scalar w) const {
	Scalar cross_area = extrusion.crossSectionArea(h, w);
	Scalar length = segment.length();
	return cross_area * length;
}

void GantryConfig::set_rapid_move_feed_rate_xy(Scalar nxyr) {
	rapidMoveFeedRateXY = nxyr;
}

void GantryConfig::set_rapid_move_feed_rate_z(Scalar nzr) {
	rapidMoveFeedRateZ = nzr;
}

void GantryConfig::set_use_e_axis(bool uea) {
	useEaxis = uea;
}

void GantryConfig::set_layer_h(Scalar lh) {
	layerH = lh;
}

void GantryConfig::set_scaling_factor(Scalar sf) {
	scalingFactor = sf;
}

void GantryConfig::set_coarseness(Scalar c) {
	coarseness = c;
}

}

<commit_msg>Comments to cut down warnings<commit_after>#include "gcoder_gantry.h"
#include "gcoder.h"
#include <cmath>
#include <iostream>
#include <sstream>

namespace mgl {

using std::ostream;
using std::endl;
using std::string;
using std::stringstream;
using libthing::LineSegment2;
using libthing::Vector2;

Gantry::Gantry(const GantryConfig& gCfg) : gantryCfg(gCfg) {
	set_current_extruder_index('A');
	set_extruding(false);
	init_to_start();
}

Scalar Gantry::get_x() const {
	return x;
}

Scalar Gantry::get_y() const {
	return y;
}

Scalar Gantry::get_z() const {
	return z;
}

Scalar Gantry::get_a() const {
	return a;
}

Scalar Gantry::get_b() const {
	return b;
}

Scalar Gantry::get_feed() const {
	return feed;
}

bool Gantry::get_extruding() const {
	return extruding;
}

unsigned char Gantry::get_current_extruder_code() const {
	return ab;
}

void Gantry::set_x(Scalar nx) {
	x = nx;
}

void Gantry::set_y(Scalar ny) {
	y = ny;
}

void Gantry::set_z(Scalar nz) {
	z = nz;
}

void Gantry::set_a(Scalar na) {
	a = na;
}

void Gantry::set_b(Scalar nb) {
	b = nb;
}

void Gantry::set_feed(Scalar nfeed) {
	feed = nfeed;
}

void Gantry::set_extruding(bool nextruding) {
	extruding = nextruding;
}

void Gantry::set_current_extruder_index(unsigned char nab) {
	ab = nab;
}

void Gantry::init_to_start() {
	set_x(gantryCfg.get_start_x());
	set_y(gantryCfg.get_start_y());
	set_z(gantryCfg.get_start_z());
	set_a(gantryCfg.get_start_a());
	set_b(gantryCfg.get_start_b());
	set_feed(gantryCfg.get_start_feed());
}

/// get axis value of the current extruder in(mm)
/// (aka mm of feedstock since the last reset this print)

Scalar Gantry::getCurrentE() const {
	switch (get_current_extruder_code()) {
	case 'A':
		return get_a();
		break;
	case 'B':
		return get_b();
		break;
	default:
	{
		string msg("Illegal extruder index ");
		msg.push_back(get_current_extruder_code());
		throw GcoderException(msg.c_str());
		return 0;
		break;
	}
	}
}

void Gantry::setCurrentE(Scalar e) {
	switch (get_current_extruder_code()) {
	case 'A':
		set_a(e);
		break;
	case 'B':
		set_b(e);
		break;
	default:
	{
		string msg("Illegal extruder index ");
		msg.push_back(get_current_extruder_code());
		throw GcoderException(msg.c_str());
		break;
	}
	}
}

void Gantry::writeSwitchExtruder(ostream& ss, Extruder &extruder) {
	ss << "( extruder " << extruder.id << " )" << endl;
	ss << "( GSWITCH T" << extruder.id << " )" << endl;
	ss << "( TODO: add offset management to Gantry )" << endl;
	ab = extruder.code;
	ss << endl;
}

Scalar Gantry::volumetricE(const Extruder &extruder,
		const Extrusion &extrusion,
		Scalar vx, Scalar vy, Scalar /*vz*/,
		Scalar h, Scalar w) const {
	//There isn't yet a LineSegment3, so for now I'm assuming that only 2d
	//segments get extruded
	LineSegment2 seg(Vector2(get_x(), get_y()), Vector2(vx, vy));
	Scalar seg_volume = gantryCfg.segmentVolume(extruder, extrusion, seg, h, w);

	Scalar feed_cross_area = extruder.feedCrossSectionArea();

	Scalar feed_len = seg_volume / feed_cross_area;

	return feed_len + getCurrentE();
}

/*if extruder and extrusion are null we don't extrude*/
void Gantry::g1(std::ostream &ss,
		const Extruder *extruder, const Extrusion *extrusion,
		Scalar gx, Scalar gy, Scalar gz, Scalar gfeed,
		Scalar h, Scalar w,
		const char *comment = NULL) {

	bool doX = true;
	bool doY = true;
	bool doZ = true;
	bool doFeed = true;
	bool doE = false;
	Scalar me = getCurrentE();

	PointType relativeVector(gx - get_x(), gy - get_y());

	if (!libthing::tequals(get_x(), gx, SAMESAME_TOL)) {
		doX = true;
	}
	if (!libthing::tequals(get_y(), gy, SAMESAME_TOL)) {
		doY = true;
	}
	if (!libthing::tequals(get_z(), gz, SAMESAME_TOL)) {
		doZ = true;
	}
	if (!libthing::tequals(get_feed(), gfeed, SAMESAME_TOL)) {
		doFeed = true;
	}
	if (get_extruding() && extruder && extrusion &&
			extruder->isVolumetric()) {
		doE = true;
		me = volumetricE(*extruder, *extrusion, gx, gy, gz, h, w);
		if(libthing::tequals(me, getCurrentE(), 0.0) ||
				relativeVector.magnitude() <= gantryCfg.get_coarseness())
			return;
	}
	g1Motion(ss, gx, gy, gz, me, gfeed, h, w, comment,
			doX, doY, doZ, doE, doFeed);
}

void Gantry::squirt(std::ostream &ss,
        const Vector2 &/*lineStart*/,
		const Extruder &extruder,
        const Extrusion &/*extrusion*/) {
	if(get_extruding())
		return;
	if (extruder.isVolumetric()) {
		g1Motion(ss, get_x(), get_y(), get_z(),
				getCurrentE() + extruder.retractDistance
				+ extruder.restartExtraDistance,
                extruder.retractRate * gantryCfg.get_scaling_factor(),
				FLUID_H, FLUID_W,
				"squirt", false, false, false, true, true); //only E and F
	} else {
		//we don't support RPM anymore
	}

	set_extruding(true);
}

void Gantry::snort(std::ostream &ss,
        const Vector2 &/*lineEnd*/,
		const Extruder &extruder,
        const Extrusion &/*extrusion*/) {
	if(!get_extruding())
		return;
	if (extruder.isVolumetric()) {
		g1Motion(ss, get_x(), get_y(), get_z(),
				getCurrentE() - extruder.retractDistance,
				extruder.retractRate * gantryCfg.get_scaling_factor(),
                FLUID_H, FLUID_W, "snort",
				false, false, false, true, true); //only E and F
	} else {
		//we don't support RPM anymore
	}

	set_extruding(false);
}

void Gantry::g1Motion(std::ostream &ss, Scalar mx, Scalar my, Scalar mz,
		Scalar me, Scalar mfeed, Scalar /*h*/, Scalar /*w*/,
		const char *g1Comment, bool doX,
		bool doY, bool doZ, bool doE, bool doFeed) {

	// not do something is not an option .. under certain conditions
#ifdef STRONG_CHECKING
	if (!(doX || doY || doZ || doFeed)) {
		stringstream ss;
		ss << "G1 without moving where x=" << x << ", y=" << y << ", z=" << z << ", feed=" << feed;
		GcoderException mixup(ss.str().c_str());
		throw mixup;
	}
#endif

	// our moto: don't be bad!
	bool bad = false;
	if (fabs(mx) > MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM) bad = true;
	if (fabs(my) > MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM) bad = true;
	if (fabs(mz) > MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM) bad = true;
	if (mfeed <= 0 || mfeed > 100000) bad = true;

	if (bad) {
		stringstream ss;
		ss << "Illegal G1 move where x=" << mx << ", y=" << my << ", z=" << mz << ", feed=" << mfeed;
		GcoderException mixup(ss.str().c_str());
		throw mixup;
	}

	unsigned char ss_axis =
			(gantryCfg.get_use_e_axis() ? 'E' :
			get_current_extruder_code());

	ss << "G1";
	if (doX) ss << " X" << mx;
	if (doY) ss << " Y" << my;
	if (doZ) ss << " Z" << mz;
	if (doFeed) ss << " F" << mfeed;
	if (doE) ss << " " << ss_axis << me;
	if (g1Comment) ss << " (" << g1Comment << ")";
	ss << endl;

	// if(feed >= 5000) assert(0);

	// update state machine
	if (doX) set_x(mx);
	if (doY) set_y(my);
	if (doZ) set_z(mz);
	if (doFeed) set_feed(mfeed);
	if (doE) setCurrentE(me);
}

GantryConfig::GantryConfig() {
	set_start_x(MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM);
	set_start_y(MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM);
	set_start_z(MUCH_LARGER_THAN_THE_BUILD_PLATFORM_MM);
	set_start_a(0);
	set_start_b(0);
	set_start_feed(0);
}

Scalar GantryConfig::get_start_x() const {
	return sx;
}

Scalar GantryConfig::get_start_y() const {
	return sy;
}

Scalar GantryConfig::get_start_z() const {
	return sz;
}

Scalar GantryConfig::get_start_a() const {
	return sa;
}

Scalar GantryConfig::get_start_b() const {
	return sb;
}

Scalar GantryConfig::get_start_feed() const {
	return sfeed;
}

void GantryConfig::set_start_x(Scalar nx) {
	sx = nx;
}

void GantryConfig::set_start_y(Scalar ny) {
	sy = ny;
}

void GantryConfig::set_start_z(Scalar nz) {
	sz = nz;
}

void GantryConfig::set_start_a(Scalar na) {
	sa = na;
}

void GantryConfig::set_start_b(Scalar nb) {
	sb = nb;
}

void GantryConfig::set_start_feed(Scalar nfeed) {
	sfeed = nfeed;
}

Scalar GantryConfig::get_rapid_move_feed_rate_xy() const {
	return rapidMoveFeedRateXY;
}

Scalar GantryConfig::get_rapid_move_feed_rate_z() const {
	return rapidMoveFeedRateZ;
}

bool GantryConfig::get_use_e_axis() const {
	return useEaxis;
}

Scalar GantryConfig::get_layer_h() const {
	return layerH;
}

Scalar GantryConfig::get_scaling_factor() const {
	return scalingFactor;
}

Scalar GantryConfig::get_coarseness() const {
	return coarseness;
}

Scalar GantryConfig::segmentVolume(const Extruder &, // extruder,
		const Extrusion &extrusion,
		LineSegment2 &segment, Scalar h, Scalar w) const {
	Scalar cross_area = extrusion.crossSectionArea(h, w);
	Scalar length = segment.length();
	return cross_area * length;
}

void GantryConfig::set_rapid_move_feed_rate_xy(Scalar nxyr) {
	rapidMoveFeedRateXY = nxyr;
}

void GantryConfig::set_rapid_move_feed_rate_z(Scalar nzr) {
	rapidMoveFeedRateZ = nzr;
}

void GantryConfig::set_use_e_axis(bool uea) {
	useEaxis = uea;
}

void GantryConfig::set_layer_h(Scalar lh) {
	layerH = lh;
}

void GantryConfig::set_scaling_factor(Scalar sf) {
	scalingFactor = sf;
}

void GantryConfig::set_coarseness(Scalar c) {
	coarseness = c;
}

}

<|endoftext|>


<commit_before>/*
 * SOPMQ - Scalable optionally persistent message queue
 * Copyright 2014 InWorldz, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "gtest/gtest.h"

#include "message_queue.h"
#include "vector_clock.h"
#include "node_clock.h"
#include "util.h"

#include <boost/uuid/uuid.hpp>

using namespace sopmq::node;

TEST(MessageQueueTest, MessageQueueBasicOrdering)
{
    message_queue3 mq("abcde");

    node_clock a1 = {1, 1, 1};
    node_clock b1 = {2, 1, 0};
    node_clock c1 = {3, 1, 1};

    vector_clock3 m1clock;
    m1clock.set(0, a1);
    m1clock.set(1, b1);
    m1clock.set(2, c1);

    auto m1id = sopmq::shared::util::random_uuid();
    std::string m1content("message1");
    mq.enqueue(m1id, &m1content, 5);
    mq.stamp(m1id, m1clock);

    node_clock a2 = {1, 1, 2};
    node_clock b2 = {2, 1, 2};
    node_clock c2 = {3, 1, 1};

    vector_clock3 m2clock;
    m2clock.set(0, a2);
    m2clock.set(1, b2);
    m2clock.set(2, c2);

    auto m2id = sopmq::shared::util::random_uuid();
    std::string m2content("message2");
    mq.enqueue(m2id, &m2content, 5);
    mq.stamp(m2id, m2clock);

    node_clock a3 = {1, 1, 2};
    node_clock b3 = {2, 1, 3};
    node_clock c3 = {3, 1, 2};

    vector_clock3 m3clock;
    m3clock.set(0, a3);
    m3clock.set(1, b3);
    m3clock.set(2, c3);

    auto m3id = sopmq::shared::util::random_uuid();
    std::string m3content("message3");
    mq.enqueue(m3id, &m3content, 5);
    mq.stamp(m3id, m3clock);

    auto messages = mq.peekAll();
    ASSERT_EQ(m1id, messages[0]->id());
    ASSERT_EQ(m2id, messages[1]->id());
    ASSERT_EQ(m3id, messages[2]->id());
}<commit_msg>Add messages out of order for good measure<commit_after>/*
 * SOPMQ - Scalable optionally persistent message queue
 * Copyright 2014 InWorldz, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "gtest/gtest.h"

#include "message_queue.h"
#include "vector_clock.h"
#include "node_clock.h"
#include "util.h"

#include <boost/uuid/uuid.hpp>

using namespace sopmq::node;

TEST(MessageQueueTest, MessageQueueBasicOrdering)
{
    message_queue3 mq("abcde");

    node_clock a1 = {1, 1, 1};
    node_clock b1 = {2, 1, 0};
    node_clock c1 = {3, 1, 1};

    vector_clock3 m1clock;
    m1clock.set(0, a1);
    m1clock.set(1, b1);
    m1clock.set(2, c1);

    auto m1id = sopmq::shared::util::random_uuid();
    std::string m1content("message1");
    mq.enqueue(m1id, &m1content, 5);
    mq.stamp(m1id, m1clock);

    node_clock a3 = {1, 1, 2};
    node_clock b3 = {2, 1, 3};
    node_clock c3 = {3, 1, 2};

    vector_clock3 m3clock;
    m3clock.set(0, a3);
    m3clock.set(1, b3);
    m3clock.set(2, c3);

    auto m3id = sopmq::shared::util::random_uuid();
    std::string m3content("message3");
    mq.enqueue(m3id, &m3content, 5);
    mq.stamp(m3id, m3clock);

    node_clock a2 = {1, 1, 2};
    node_clock b2 = {2, 1, 2};
    node_clock c2 = {3, 1, 1};

    vector_clock3 m2clock;
    m2clock.set(0, a2);
    m2clock.set(1, b2);
    m2clock.set(2, c2);

    auto m2id = sopmq::shared::util::random_uuid();
    std::string m2content("message2");
    mq.enqueue(m2id, &m2content, 5);
    mq.stamp(m2id, m2clock);

    auto messages = mq.peekAll();
    ASSERT_EQ(m1id, messages[0]->id());
    ASSERT_EQ(m2id, messages[1]->id());
    ASSERT_EQ(m3id, messages[2]->id());
}<|endoftext|>


<commit_before>#ifndef MUTEXES_H
#define MUTEXES_H

#ifndef single_threaded
	#include<boost/thread/mutex.hpp>
	#include<boost/scoped_ptr.hpp>
#endif
#include<boost/noncopyable.hpp>

class AppLock;
class AppTryLock;

class AppMutex : boost::noncopyable {
private:
	#ifndef single_threaded
		boost::scoped_ptr<boost::try_mutex> mp;
	#endif
public:
	AppMutex() {
		#ifndef single_threaded
			if(!single_threaded) {
				mp.reset(new boost::try_mutex());
			}
		#endif
	}
	friend class AppLock;
	friend class AppTryLock;
};

class AppLock : boost::noncopyable {
private:
	#ifndef single_threaded
		boost::scoped_ptr<boost::try_mutex::scoped_lock > lp;
	#endif
	AppLock(); // disallowed!
public:
	AppLock(AppMutex& m) {
		#ifndef single_threaded
			if(!single_threaded) {
				lp.reset(new boost::try_mutex::scoped_lock(*m.mp));
			}
		#endif
	}
};

class AppTryLock : boost::noncopyable {
private:
	#ifndef single_threaded
		boost::scoped_ptr<boost::try_mutex::scoped_try_lock> lp;
	#endif
	AppTryLock(); //disallowed!
public:
	AppTryLock(AppMutex& m) {
		#ifndef single_threaded
			if(!single_threaded) {
				lp.reset(new boost::try_mutex::scoped_try_lock(*m.mp));
			}
		#endif
	}
	/*returns true if we successfully acquired the lock*/
	operator bool(void) const {
		#ifndef single_threaded
			if(!lp) return 1;
			return lp->locked();
		#else
			return 1;
		#endif
	}
};

#endif // MUTEXES_H

<commit_msg>inc/mutexes.hpp: Changed to use os/thread.hpp instead of Boost.Thread<commit_after>#ifndef MUTEXES_H
#define MUTEXES_H

#ifndef single_threaded
	#include"thread.hpp"
	#include<boost/scoped_ptr.hpp>
#endif
#include<boost/noncopyable.hpp>

class AppLock;
class AppTryLock;

class AppMutex : boost::noncopyable {
private:
	#ifndef single_threaded
		boost::scoped_ptr<Mutex> mp;
	#endif
public:
	AppMutex() {
		#ifndef single_threaded
			if(!single_threaded) {
				mp.reset(new Mutex());
			}
		#endif
	}
	friend class AppLock;
	friend class AppTryLock;
};

class AppLock : boost::noncopyable {
private:
	#ifndef single_threaded
		boost::scoped_ptr<Lock> lp;
	#endif
	AppLock(); // disallowed!
public:
	AppLock(AppMutex& m) {
		#ifndef single_threaded
			if(!single_threaded) {
				lp.reset(new Lock(*m.mp));
			}
		#endif
	}
};

class AppTryLock : boost::noncopyable {
private:
	#ifndef single_threaded
		boost::scoped_ptr<TryLock> lp;
	#endif
	AppTryLock(); //disallowed!
public:
	AppTryLock(AppMutex& m) {
		#ifndef single_threaded
			if(!single_threaded) {
				lp.reset(new TryLock(*m.mp));
			}
		#endif
	}
	/*safe bool idiom*/
	inline void unspecified_bool(void) const { }
	typedef void (AppTryLock::*unspecified_bool_type)(void) const;
	operator unspecified_bool_type(void) const {
		#ifndef single_threaded
			if(!lp) return &AppTryLock::unspecified_bool;
			return (*lp) ? &AppTryLock::unspecified_bool : 0;
		#else
			return &AppTryLock::unspecified_bool;
		#endif
	}
};

#endif // MUTEXES_H

<|endoftext|>


<commit_before>#include "ElementComparator.h"
#include "catch.hpp"
#include "refract/Element.h"

using namespace drafter;
using S = refract::StringElement;
using N = refract::NumberElement;

SCENARIO("Compare equality of elements", "[Element][comparate][equal]")
{

    GIVEN("Two empty primitive elements of same type")
    {

        auto first = make_empty<S>();
        auto second = make_empty<S>();

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements of diferent type")
    {

        auto first = make_empty<S>();
        auto second = make_empty<N>();

        WHEN("it is compared")
        {
            THEN("it is recognized as non-equal")
            {
                REQUIRE(false == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two primitive elements of same type with same value")
    {

        auto first = make_element<S>("a");
        auto second = make_element<S>("a");

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two primitive elements of same type with different value")
    {

        auto first = make_element<S>("a");
        auto second = make_element<S>("b");

        WHEN("it is compared")
        {
            THEN("it is recognized as non-equal")
            {
                REQUIRE(false == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements of same type with different element name")
    {

        auto first = make_element<S>();
        first->element("A");
        auto second = make_element<S>();

        WHEN("it is compared")
        {
            THEN("it is recognized as non-equal")
            {
                REQUIRE(false == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive different InfoElements")
    {

        auto first = make_element<S>();
        first->attributes().set("key", make_element<S>("value"));

        auto second = make_element<S>();

        WHEN("it is compared")
        {
            THEN("it is recognized as non-equal")
            {
                REQUIRE(false == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements with same InfoElements")
    {

        auto first = make_element<S>();
        first->attributes().set("key", make_element<S>("value"));

        auto second = make_element<S>();
        second->attributes().set("key", make_element<S>("value"));

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements with different InfoElements value")
    {

        auto first = make_element<S>();
        first->attributes().set("key", make_element<S>("value"));

        auto second = make_element<S>();
        second->attributes().set("key", make_element<S>("another value"));

        WHEN("it is compared")
        {
            THEN("it is recognized as non-equal")
            {
                REQUIRE(false == visit(*first, ElementComparator{ *second }));
            }
        }
    }
}

SCENARIO("Compare equality of elements with sourceMaps", "[Element][comparate][equal]")
{
    GIVEN("Two empty primitive elements with different sourceMap value")
    {

        auto first = make_element<S>();
        first->attributes().set("sourceMap", make_element<S>("value"));

        auto second = make_element<S>();
        second->attributes().set("sourceMap", make_element<S>("another value"));

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements first with sourceMap")
    {

        auto first = make_element<S>();
        first->attributes().set("sourceMap", make_element<S>("value"));

        auto second = make_element<S>();

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements second with sourceMap")
    {

        auto first = make_element<S>();

        auto second = make_element<S>();
        second->attributes().set("sourceMap", make_element<S>("value"));

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }
}
<commit_msg>Fix typo<commit_after>#include "ElementComparator.h"
#include "catch.hpp"
#include "refract/Element.h"

using namespace drafter;
using S = refract::StringElement;
using N = refract::NumberElement;

SCENARIO("Compare equality of elements", "[Element][comparator][equal]")
{

    GIVEN("Two empty primitive elements of same type")
    {

        auto first = make_empty<S>();
        auto second = make_empty<S>();

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements of diferent type")
    {

        auto first = make_empty<S>();
        auto second = make_empty<N>();

        WHEN("it is compared")
        {
            THEN("it is recognized as non-equal")
            {
                REQUIRE(false == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two primitive elements of same type with same value")
    {

        auto first = make_element<S>("a");
        auto second = make_element<S>("a");

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two primitive elements of same type with different value")
    {

        auto first = make_element<S>("a");
        auto second = make_element<S>("b");

        WHEN("it is compared")
        {
            THEN("it is recognized as non-equal")
            {
                REQUIRE(false == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements of same type with different element name")
    {

        auto first = make_element<S>();
        first->element("A");
        auto second = make_element<S>();

        WHEN("it is compared")
        {
            THEN("it is recognized as non-equal")
            {
                REQUIRE(false == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive different InfoElements")
    {

        auto first = make_element<S>();
        first->attributes().set("key", make_element<S>("value"));

        auto second = make_element<S>();

        WHEN("it is compared")
        {
            THEN("it is recognized as non-equal")
            {
                REQUIRE(false == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements with same InfoElements")
    {

        auto first = make_element<S>();
        first->attributes().set("key", make_element<S>("value"));

        auto second = make_element<S>();
        second->attributes().set("key", make_element<S>("value"));

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements with different InfoElements value")
    {

        auto first = make_element<S>();
        first->attributes().set("key", make_element<S>("value"));

        auto second = make_element<S>();
        second->attributes().set("key", make_element<S>("another value"));

        WHEN("it is compared")
        {
            THEN("it is recognized as non-equal")
            {
                REQUIRE(false == visit(*first, ElementComparator{ *second }));
            }
        }
    }
}

SCENARIO("Compare equality of elements with sourceMaps", "[Element][comparator][equal]")
{
    GIVEN("Two empty primitive elements with different sourceMap value")
    {

        auto first = make_element<S>();
        first->attributes().set("sourceMap", make_element<S>("value"));

        auto second = make_element<S>();
        second->attributes().set("sourceMap", make_element<S>("another value"));

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements first with sourceMap")
    {

        auto first = make_element<S>();
        first->attributes().set("sourceMap", make_element<S>("value"));

        auto second = make_element<S>();

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }

    GIVEN("Two empty primitive elements second with sourceMap")
    {

        auto first = make_element<S>();

        auto second = make_element<S>();
        second->attributes().set("sourceMap", make_element<S>("value"));

        WHEN("it is compared")
        {
            THEN("it is recognized as equal")
            {
                REQUIRE(true == visit(*first, ElementComparator{ *second }));
            }
        }
    }
}
<|endoftext|>


<commit_before>#pragma once

#include <vector>
#include <tuple>
#include <utility>

namespace helene
{

namespace soa_detail
{
template <class MemberPointerType>
struct deduce_member_pointer;

template <class MemberType, class ObjectType>
struct deduce_member_pointer<MemberType ObjectType::*>
{
    typedef MemberType member_type;
    typedef ObjectType object_type;
};

template <class MemberPointerType>
using member_type_t =
    typename deduce_member_pointer<MemberPointerType>::member_type;

template <class MemberPointerType>
using object_type_t =
    typename deduce_member_pointer<MemberPointerType>::object_type;
}

template <class PointerType, PointerType PointerValue>
struct member_reference
{
    static constexpr PointerType pointer_value = PointerValue;
};

template <class T, class... MemberRefs>
class element_proxy;

template <class T, class... PointerTypes, PointerTypes... PointerValues>
class element_proxy<T, member_reference<PointerTypes, PointerValues>...>
{
    template <std::size_t... S>
    T
    make_dispatch(std::index_sequence<S...>) const
    {
        return T{*std::get<S>(pointers_)...};
    }

    template <class FirstRef, class... RestRefs>
    struct assignment_helper
    {
        template <std::size_t S, std::size_t... Ss>
        static void
        assign(std::tuple<soa_detail::member_type_t<PointerTypes>*...>& tpl,
               const T& value,
               std::index_sequence<S, Ss...>)
        {
            *std::get<S>(tpl) = value.*FirstRef::pointer_value;

            assignment_helper<RestRefs...>::assign(
                tpl, value, std::index_sequence<Ss...>());
        }
    };

    template <class LastRef>
    struct assignment_helper<LastRef>
    {

        template <std::size_t S>
        static void
        assign(std::tuple<soa_detail::member_type_t<PointerTypes>*...>& tpl,
               const T& value,
               std::index_sequence<S>)
        {

            *std::get<S>(tpl) = value.*LastRef::pointer_value;
        }
    };

public:
    element_proxy(soa_detail::member_type_t<PointerTypes>&... args)
        : pointers_(&args...)
    {
    }

    operator T() const
    {
        return make_dispatch(std::index_sequence_for<PointerTypes...>());
    }

    element_proxy&
    operator=(const T& value)
    {
        assignment_helper<member_reference<PointerTypes, PointerValues>...>::
            assign(
                pointers_, value, std::index_sequence_for<PointerTypes...>());

        return *this;
    }

private:
    std::tuple<soa_detail::member_type_t<PointerTypes>*...> pointers_;
};

// helper to access respective parents that are multiply inherited
template <class FirstParent, class... RestParents>
struct parent_helper
{
    template <class SoaType>
    static std::size_t
    size(const SoaType& s)
    {
        return s.FirstParent::members_.size();
    }

    template <class SoaType>
    static void
    push_back(SoaType& s, const typename SoaType::value_type& value)
    {
        s.FirstParent::members_.push_back(value.*FirstParent::pointer);
        parent_helper<RestParents...>::push_back(s, value);
    }
};

template <class LastParent>
struct parent_helper<LastParent>
{
    template <class SoaType>
    static std::size_t
    size(const SoaType& s)
    {
        return s.LastParent::members_.size();
    }

    template <class SoaType>
    static void
    push_back(SoaType& s, const typename SoaType::value_type& value)
    {
        s.LastParent::members_.push_back(value.*LastParent::pointer);
    }
};

template <class MemberPointerType, MemberPointerType MemberPointerValue>
class member_container
{
public:
    typedef soa_detail::member_type_t<MemberPointerType> member_type;
    typedef soa_detail::object_type_t<MemberPointerType> object_type;

    static constexpr MemberPointerType pointer = MemberPointerValue;

public:
    member_container() = default;

    std::vector<member_type> members_;
};

template <class T, class... MemberContainer>
class soa;

template <class T, class... MemberPtrTypes, MemberPtrTypes... MemberPtrValues>
class soa<T, member_container<MemberPtrTypes, MemberPtrValues>...>
    : public member_container<MemberPtrTypes, MemberPtrValues>...
{
public:
    typedef T value_type;
    typedef element_proxy<T,
                          member_reference<MemberPtrTypes, MemberPtrValues>...>
        proxy_value_type;

public:
    soa() : member_container<MemberPtrTypes, MemberPtrValues>()...
    {
    }

    std::size_t
    size() const
    {
        return parent_helper<
            member_container<MemberPtrTypes, MemberPtrValues>...>::size(*this);
    }

    void
    push_back(const T& value)
    {
        parent_helper<member_container<MemberPtrTypes, MemberPtrValues>...>::
            push_back(*this, value);
    }

    proxy_value_type operator[](std::size_t n)
    {
        return proxy_value_type(
            member_container<MemberPtrTypes, MemberPtrValues>::members_[n]...);
    }

    const proxy_value_type operator[](std::size_t n) const
    {
        return proxy_value_type(
            member_container<MemberPtrTypes, MemberPtrValues>::members_[n]...);
    }
};
}
<commit_msg>Modify assignment_helper to avoid internal compiler error in gcc. 	modified:   include/soa.hpp<commit_after>#pragma once

#include <vector>
#include <tuple>
#include <utility>

namespace helene
{

namespace soa_detail
{
template <class MemberPointerType>
struct deduce_member_pointer;

template <class MemberType, class ObjectType>
struct deduce_member_pointer<MemberType ObjectType::*>
{
    typedef MemberType member_type;
    typedef ObjectType object_type;
};

template <class MemberPointerType>
using member_type_t =
    typename deduce_member_pointer<MemberPointerType>::member_type;

template <class MemberPointerType>
using object_type_t =
    typename deduce_member_pointer<MemberPointerType>::object_type;
}

template <class PointerType, PointerType PointerValue>
struct member_reference
{
    static constexpr PointerType pointer_value = PointerValue;
};

template <class T, class... MemberRefs>
class element_proxy;

template <class T, class... PointerTypes, PointerTypes... PointerValues>
class element_proxy<T, member_reference<PointerTypes, PointerValues>...>
{
    template <std::size_t... S>
    T
    make_dispatch(std::index_sequence<S...>) const
    {
        return T{*std::get<S>(pointers_)...};
    }

    template <std::size_t S, class FirstRef, class... RestRefs>
    struct assignment_helper
    {
        static void
        assign(std::tuple<soa_detail::member_type_t<PointerTypes>*...>& tpl,
               const T& value)
        {
            *std::get<S>(tpl) = value.*FirstRef::pointer_value;

            assignment_helper<S + 1, RestRefs...>::assign(tpl, value);
        }
    };

    template <std::size_t S, class LastRef>
    struct assignment_helper<S, LastRef>
    {

        static void
        assign(std::tuple<soa_detail::member_type_t<PointerTypes>*...>& tpl,
               const T& value)
        {
            *std::get<S>(tpl) = value.*LastRef::pointer_value;
        }
    };

public:
    element_proxy(soa_detail::member_type_t<PointerTypes>&... args)
        : pointers_(&args...)
    {
    }

    operator T() const
    {
        return make_dispatch(std::index_sequence_for<PointerTypes...>());
    }

    element_proxy&
    operator=(const T& value)
    {
        assignment_helper<0, member_reference<PointerTypes, PointerValues>...>::
            assign(pointers_, value);

        return *this;
    }

private:
    std::tuple<soa_detail::member_type_t<PointerTypes>*...> pointers_;
};

// helper to access respective parents that are multiply inherited
template <class FirstParent, class... RestParents>
struct parent_helper
{
    template <class SoaType>
    static std::size_t
    size(const SoaType& s)
    {
        return s.FirstParent::members_.size();
    }

    template <class SoaType>
    static void
    push_back(SoaType& s, const typename SoaType::value_type& value)
    {
        s.FirstParent::members_.push_back(value.*FirstParent::pointer);
        parent_helper<RestParents...>::push_back(s, value);
    }
};

template <class LastParent>
struct parent_helper<LastParent>
{
    template <class SoaType>
    static std::size_t
    size(const SoaType& s)
    {
        return s.LastParent::members_.size();
    }

    template <class SoaType>
    static void
    push_back(SoaType& s, const typename SoaType::value_type& value)
    {
        s.LastParent::members_.push_back(value.*LastParent::pointer);
    }
};

template <class MemberPointerType, MemberPointerType MemberPointerValue>
class member_container
{
public:
    typedef soa_detail::member_type_t<MemberPointerType> member_type;
    typedef soa_detail::object_type_t<MemberPointerType> object_type;

    static constexpr MemberPointerType pointer = MemberPointerValue;

public:
    member_container() = default;

    std::vector<member_type> members_;
};

template <class T, class... MemberContainer>
class soa;

template <class T, class... MemberPtrTypes, MemberPtrTypes... MemberPtrValues>
class soa<T, member_container<MemberPtrTypes, MemberPtrValues>...>
    : public member_container<MemberPtrTypes, MemberPtrValues>...
{
public:
    typedef T value_type;
    typedef element_proxy<T,
                          member_reference<MemberPtrTypes, MemberPtrValues>...>
        proxy_value_type;

public:
    soa() : member_container<MemberPtrTypes, MemberPtrValues>()...
    {
    }

    std::size_t
    size() const
    {
        return parent_helper<
            member_container<MemberPtrTypes, MemberPtrValues>...>::size(*this);
    }

    void
    push_back(const T& value)
    {
        parent_helper<member_container<MemberPtrTypes, MemberPtrValues>...>::
            push_back(*this, value);
    }

    proxy_value_type operator[](std::size_t n)
    {
        return proxy_value_type(
            member_container<MemberPtrTypes, MemberPtrValues>::members_[n]...);
    }

    const proxy_value_type operator[](std::size_t n) const
    {
        return proxy_value_type(
            member_container<MemberPtrTypes, MemberPtrValues>::members_[n]...);
    }
};
}
<|endoftext|>