<commit_before>/// Causal Dynamical Triangulations in C++ using CGAL
///
/// Copyright © 2015-2018 Adam Getchell
///
/// Creates foliated spherical triangulations
///
/// The number of desired timeslices is given, and
/// successive spheres are created with increasing radii.
/// Each vertex at a given radius is assigned a timeslice so that the
/// entire triangulation will have a preferred foliation of time.
///
/// \done Insert a 3-sphere into the triangulation data structure.
/// \done Assign each 3-sphere a unique timeslice.
/// \done Iterate over the number of desired timeslices.
/// \done Check/fix issues for large values of simplices and timeslices.
/// \done Iterate over cells and check timeslices of vertices don't differ
///        by more than 1.
/// \done Gather ratio of cells with bad/good foliation.
///        Adjust value of radius to minimize.
///        Recheck the whole triangulation when finished.
/// \done When a cell contains a bad foliation, delete it. Recheck.
/// \done Fixup Delaunay triangulation after bad cells have been deleted.
/// \done Re-written with std::unique_ptr<T> and
/// .
/// Efficient Pure Functional Programming in C++ Using Move Semantics
/// \done
/// Const Correctness.
/// \done Function documentation.
/// \done Multi-threaded operations using Intel TBB.
/// \done Debugging output toggled by macros.

/// @file S3Triangulation.hpp
/// @brief Functions on 3D Spherical Delaunay Triangulations
/// @author Adam Getchell

#ifndef INCLUDE_S3TRIANGULATION_HPP_
#define INCLUDE_S3TRIANGULATION_HPP_

/// Toggles detailed per-simplex debugging output
#define DETAILED_DEBUGGING
#undef DETAILED_DEBUGGING

// CGAL headers
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Triangulation_cell_base_with_info_3.h>
#include <CGAL/Triangulation_vertex_base_with_info_3.h>
#include <CGAL/point_generators_3.h>

// C++ headers
#include <algorithm>
#include <memory>
#include <set>
#include <stdexcept>
#include <tuple>
#include <utility>
#include <vector>

// CDT headers
#include <Utilities.hpp>

using K             = CGAL::Exact_predicates_inexact_constructions_kernel;
using Triangulation = CGAL::Triangulation_3<K>;
// Used so that each timeslice is assigned an integer
using Vb = CGAL::Triangulation_vertex_base_with_info_3<std::size_t, K>;
using Cb = CGAL::Triangulation_cell_base_with_info_3<std::size_t, K>;

// Parallel operations
#ifdef CGAL_LINKED_WITH_TBB
using Tds = CGAL::Triangulation_data_structure_3<Vb, Cb, CGAL::Parallel_tag>;
#else
using Tds = CGAL::Triangulation_data_structure_3<Vb, Cb>;
#endif
using Delaunay3       = CGAL::Delaunay_triangulation_3<K, Tds>;
using Cell_handle     = Delaunay3::Cell_handle;
using Vertex_handle   = Delaunay3::Vertex_handle;
using Locate_type     = Delaunay3::Locate_type;
using Point           = Delaunay3::Point;
using Edge_handle     = std::tuple<Cell_handle, std::size_t, std::size_t>;
using Causal_vertices = std::vector<std::pair<Point, std::size_t>>;
using Move_tracker    = std::array<std::size_t, 5>;

enum class move_type
{
  TWO_THREE = 0,
  THREE_TWO = 1,
  TWO_SIX   = 2,
  SIX_TWO   = 3,
  FOUR_FOUR = 4
};

/// The maximum number of passes to fix invalidly foliated simplices
static constexpr std::size_t MAX_FOLIATION_FIX_PASSES = 500;

/// The dimensionality of the Delaunay triangulation
static constexpr std::size_t DIMENSION = 3;

/// Initial radius and radial factor
static constexpr double INITIAL_RADIUS = 1.0;
static constexpr double RADIAL_FACTOR  = 1.0;

/// @brief Fix simplices with incorrect foliation
///
/// This function iterates over all of the cells in the triangulation.
/// Within each cell, it iterates over all of the vertices and reads timeslices.
/// Validity of the cell is first checked by the **is_valid()** function.
/// The foliation validity is then checked by finding maximum and minimum
/// timeslices for all the vertices of a cell and ensuring that the difference
/// is exactly 1.
/// If a cell has a bad foliation, the vertex with the highest timeslice is
/// deleted. The Delaunay triangulation is then recomputed on the remaining
/// vertices.
/// This function is repeatedly called by fix_triangulation() up to
/// **MAX_FOLIATION_FIX_PASSES** times.
///
/// @param universe_ptr A std::unique_ptr<Delaunay> to the triangulation
/// @returns A boolean value if there are invalid simplices
template <typename Manifold>
[[nodiscard]] auto fix_timeslices(Manifold&& universe_ptr)
{
  std::size_t             min_time{0};
  std::size_t             max_time{0};
  std::size_t             valid{0};
  std::size_t             invalid{0};
  std::size_t             max_vertex{0};
  std::set<Vertex_handle> deleted_vertices;

  // Iterate over all cells in the Delaunay triangulation
  for (Delaunay3::Finite_cells_iterator cit =
           universe_ptr->finite_cells_begin();
       cit != universe_ptr->finite_cells_end(); ++cit)
  {
    if (cit->is_valid())
    {  // Valid cell
      min_time = cit->vertex(0)->info();
      max_time = min_time;
#ifdef DETAILED_DEBUGGING
      bool this_cell_foliation_valid = true;
#endif
      // Iterate over all vertices in the cell
      for (std::size_t i = 0; i < 4; ++i)
      {
        auto current_time = cit->vertex(i)->info();

        // Classify extreme values
        if (current_time < min_time) min_time = current_time;
        if (current_time > max_time)
        {
          max_time   = current_time;
          max_vertex = i;
        }
      }  // Finish iterating over vertices
      // There should be a difference of 1 between min_time and max_time
      if (max_time - min_time != 1)
      {
        invalid++;
#ifdef DETAILED_DEBUGGING
        this_cell_foliation_valid = false;
#endif
        // Single-threaded delete max vertex
        // universe_ptr->remove(cit->vertex(max_vertex));

        // Parallel delete std::set of max_vertex for all invalid cells
        deleted_vertices.emplace(cit->vertex(max_vertex));
      }
      else
      {
        ++valid;
      }

#ifdef DETAILED_DEBUGGING
      std::cout << "Foliation for cell is "
                << ((this_cell_foliation_valid) ? "valid." : "invalid.\n");
      for (auto i = 0; i < 4; ++i)
      {
        std::cout << "Vertex " << i << " is " << cit->vertex(i)->point()
                  << " with timeslice " << cit->vertex(i)->info() << "\n";
      }
#endif
    }
    else
    {
      throw std::runtime_error("Cell handle is invalid!");
      // Or just remove the cell
      // universe_ptr->tds().delete_cell(cit);
      // This results in a possibly broken Delaunay triangulation
      // Or possibly just delete a vertex in the cell,
      // perhaps forcing a re-triangulation?
    }
  }  // Finish iterating over cells

  // Delete invalid vertices
  universe_ptr->remove(deleted_vertices.begin(), deleted_vertices.end());
  // Check that the triangulation is still valid
  // Turned off by -DCGAL_TRIANGULATION_NO_POSTCONDITIONS
  //  CGAL_triangulation_expensive_postcondition(universe_ptr->is_valid());
  if (!universe_ptr->tds().is_valid())
    throw std::logic_error("Delaunay tds invalid!");

#ifndef NDEBUG
  std::cout << "There are " << invalid << " invalid simplices and " << valid
            << " valid simplices.\n";
#endif
  return invalid == 0;
}  // fix_timeslices

/// @brief Fixes the foliation of the triangulation
///
/// Runs fix_timeslices() to fix foliation until there are no errors,
/// or MAX_FOLIATION_FIX_PASSES whichever comes first.
///
/// @param universe_ptr A std::unique_ptr<Delaunay> to the triangulation
template <typename Manifold>
void fix_triangulation(Manifold&& universe_ptr)
{
  for (std::size_t pass = 0; pass < MAX_FOLIATION_FIX_PASSES; ++pass)
  {
#ifndef NDEBUG
    std::cout << "Fix Pass #" << (pass + 1) << "\n";
#endif
    if (fix_timeslices(universe_ptr)) break;
  }
  if (!fix_timeslices(universe_ptr))
    throw std::logic_error("Delaunay triangulation not correctly foliated.");
}  // fix_triangulation()

/// @brief Inserts vertices with timeslices into Delaunay triangulation
///
/// @tparam Manifold Type of universe_ptr
/// @param universe_ptr A unique pointer to triangulation
/// @param cv A data structure of causal vertices
template <typename Manifold>
void insert_into_triangulation(Manifold&& universe_ptr, Causal_vertices cv)
{
  universe_ptr->insert(cv.begin(), cv.end());
}  // insert_into_triangulation()

/// @brief Make foliated spheres
///
/// The radius is used to denote the time value, so we can nest 2-spheres
/// such that our time foliation contains leaves of identical topology.
///
/// @param simplices The number of desired simplices in the triangulation
/// @param timeslices  The number of desired timeslices in the triangulation
/// @return A std::vector<std::pair<Point, std::size_t>> containing random
/// vertices and their corresponding timevalues
[[nodiscard]] auto inline make_foliated_sphere(const std::size_t simplices,
                                 const std::size_t timeslices,
                                 double initial_radius = INITIAL_RADIUS,
                                 double radial_factor  = RADIAL_FACTOR)
{
  //  double     radius{0};
  const auto points_per_timeslice =
      expected_points_per_simplex(DIMENSION, simplices, timeslices);
  CGAL_triangulation_precondition(points_per_timeslice >= 2);
  Causal_vertices causal_vertices;
  using Spherical_points_generator_3 = CGAL::Random_points_on_sphere_3<Point>;

  for (std::size_t i = 0; i < timeslices; ++i)
  {
    auto radius = initial_radius + static_cast<double>(i) * radial_factor;
    //    CGAL::Random_points_on_sphere_3<Point> gen{radius};
    Spherical_points_generator_3 gen{radius};
    // At each radius, generate a sphere of random points proportional to area
    for (std::size_t j = 0;
         j < static_cast<std::size_t>(points_per_timeslice * radius); ++j)
    { causal_vertices.emplace_back(std::make_pair(*gen++, i + 1)); }  // end j
  }                                                                   // end i
  return causal_vertices;
}  // make_foliated_sphere()

/// @brief Make a triangulation from foliated 2-spheres
///
/// This function creates a triangulation from successive spheres.
/// First, the number of points per leaf in the foliation is estimated given
/// the desired number of simplices.
/// Next, make_foliated_sphere() is called to generate nested spheres.
/// The radius of the sphere is assigned as the time value for each vertex
/// in that sphere, which comprises a leaf in the foliation.
/// All vertices in all spheres (along with their time values) are then
/// inserted with insert_into_triangulation() into a Delaunay triangulation
/// (see http://en.wikipedia.org/wiki/Delaunay_triangulation for details).
/// Finally, fix_triangulation() removes cells in the Delaunay triangulation
/// with invalid foliations using fix_timeslices(). A last check is performed
/// to ensure a valid Delaunay triangulation.
///
/// @param[in] simplices  The number of desired simplices in the triangulation
/// @param[in] timeslices The number of timeslices in the triangulation
/// @returns A std::unique_ptr<Delaunay> to the foliated triangulation
[[nodiscard]] auto inline make_triangulation(const std::size_t simplices,
                               const std::size_t timeslices,
                               double initial_radius = INITIAL_RADIUS,
                               double radial_factor  = RADIAL_FACTOR)
{
  std::cout << "Generating universe ... \n";

#ifdef CGAL_LINKED_WITH_TBB
  // Construct the locking data-structure
  // using the bounding-box of the points
  auto bounding_box_size = static_cast<double>(timeslices + 1);
  Delaunay::Lock_data_structure locking_ds{
      CGAL::Bbox_3{-bounding_box_size, -bounding_box_size, -bounding_box_size,
                   bounding_box_size, bounding_box_size, bounding_box_size},
      50};
  Delaunay universe{K{}, &locking_ds};
#else
  Delaunay3 universe{};
#endif

  auto universe_ptr    = std::make_unique<decltype(universe)>(universe);
  auto causal_vertices = make_foliated_sphere(simplices, timeslices,
                                              initial_radius, radial_factor);
  insert_into_triangulation(universe_ptr, causal_vertices);
  fix_triangulation(universe_ptr);
  if (!universe_ptr->is_valid())
    throw std::logic_error("Delaunay triangulation invalid!");
  return universe_ptr;
}  // make_triangulation()

#endif  // INCLUDE_S3TRIANGULATION_HPP_
<commit_msg>Formats<commit_after>/// Causal Dynamical Triangulations in C++ using CGAL
///
/// Copyright © 2015-2018 Adam Getchell
///
/// Creates foliated spherical triangulations
///
/// The number of desired timeslices is given, and
/// successive spheres are created with increasing radii.
/// Each vertex at a given radius is assigned a timeslice so that the
/// entire triangulation will have a preferred foliation of time.
///
/// \done Insert a 3-sphere into the triangulation data structure.
/// \done Assign each 3-sphere a unique timeslice.
/// \done Iterate over the number of desired timeslices.
/// \done Check/fix issues for large values of simplices and timeslices.
/// \done Iterate over cells and check timeslices of vertices don't differ
///        by more than 1.
/// \done Gather ratio of cells with bad/good foliation.
///        Adjust value of radius to minimize.
///        Recheck the whole triangulation when finished.
/// \done When a cell contains a bad foliation, delete it. Recheck.
/// \done Fixup Delaunay triangulation after bad cells have been deleted.
/// \done Re-written with std::unique_ptr<T> and
/// .
/// Efficient Pure Functional Programming in C++ Using Move Semantics
/// \done
/// Const Correctness.
/// \done Function documentation.
/// \done Multi-threaded operations using Intel TBB.
/// \done Debugging output toggled by macros.

/// @file S3Triangulation.hpp
/// @brief Functions on 3D Spherical Delaunay Triangulations
/// @author Adam Getchell

#ifndef INCLUDE_S3TRIANGULATION_HPP_
#define INCLUDE_S3TRIANGULATION_HPP_

/// Toggles detailed per-simplex debugging output
#define DETAILED_DEBUGGING
#undef DETAILED_DEBUGGING

// CGAL headers
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Triangulation_cell_base_with_info_3.h>
#include <CGAL/Triangulation_vertex_base_with_info_3.h>
#include <CGAL/point_generators_3.h>

// C++ headers
#include <algorithm>
#include <memory>
#include <set>
#include <stdexcept>
#include <tuple>
#include <utility>
#include <vector>

// CDT headers
#include <Utilities.hpp>

using K             = CGAL::Exact_predicates_inexact_constructions_kernel;
using Triangulation = CGAL::Triangulation_3<K>;
// Used so that each timeslice is assigned an integer
using Vb = CGAL::Triangulation_vertex_base_with_info_3<std::size_t, K>;
using Cb = CGAL::Triangulation_cell_base_with_info_3<std::size_t, K>;

// Parallel operations
#ifdef CGAL_LINKED_WITH_TBB
using Tds = CGAL::Triangulation_data_structure_3<Vb, Cb, CGAL::Parallel_tag>;
#else
using Tds = CGAL::Triangulation_data_structure_3<Vb, Cb>;
#endif
using Delaunay3       = CGAL::Delaunay_triangulation_3<K, Tds>;
using Cell_handle     = Delaunay3::Cell_handle;
using Vertex_handle   = Delaunay3::Vertex_handle;
using Locate_type     = Delaunay3::Locate_type;
using Point           = Delaunay3::Point;
using Edge_handle     = std::tuple<Cell_handle, std::size_t, std::size_t>;
using Causal_vertices = std::vector<std::pair<Point, std::size_t>>;
using Move_tracker    = std::array<std::size_t, 5>;

enum class move_type
{
  TWO_THREE = 0,
  THREE_TWO = 1,
  TWO_SIX   = 2,
  SIX_TWO   = 3,
  FOUR_FOUR = 4
};

/// The maximum number of passes to fix invalidly foliated simplices
static constexpr std::size_t MAX_FOLIATION_FIX_PASSES = 500;

/// The dimensionality of the Delaunay triangulation
static constexpr std::size_t DIMENSION = 3;

/// Initial radius and radial factor
static constexpr double INITIAL_RADIUS = 1.0;
static constexpr double RADIAL_FACTOR  = 1.0;

/// @brief Fix simplices with incorrect foliation
///
/// This function iterates over all of the cells in the triangulation.
/// Within each cell, it iterates over all of the vertices and reads timeslices.
/// Validity of the cell is first checked by the **is_valid()** function.
/// The foliation validity is then checked by finding maximum and minimum
/// timeslices for all the vertices of a cell and ensuring that the difference
/// is exactly 1.
/// If a cell has a bad foliation, the vertex with the highest timeslice is
/// deleted. The Delaunay triangulation is then recomputed on the remaining
/// vertices.
/// This function is repeatedly called by fix_triangulation() up to
/// **MAX_FOLIATION_FIX_PASSES** times.
///
/// @param universe_ptr A std::unique_ptr<Delaunay> to the triangulation
/// @returns A boolean value if there are invalid simplices
template <typename Manifold>
[[nodiscard]] auto fix_timeslices(Manifold&& universe_ptr)
{
  std::size_t             min_time{0};
  std::size_t             max_time{0};
  std::size_t             valid{0};
  std::size_t             invalid{0};
  std::size_t             max_vertex{0};
  std::set<Vertex_handle> deleted_vertices;

  // Iterate over all cells in the Delaunay triangulation
  for (Delaunay3::Finite_cells_iterator cit =
           universe_ptr->finite_cells_begin();
       cit != universe_ptr->finite_cells_end(); ++cit)
  {
    if (cit->is_valid())
    {  // Valid cell
      min_time = cit->vertex(0)->info();
      max_time = min_time;
#ifdef DETAILED_DEBUGGING
      bool this_cell_foliation_valid = true;
#endif
      // Iterate over all vertices in the cell
      for (std::size_t i = 0; i < 4; ++i)
      {
        auto current_time = cit->vertex(i)->info();

        // Classify extreme values
        if (current_time < min_time) min_time = current_time;
        if (current_time > max_time)
        {
          max_time   = current_time;
          max_vertex = i;
        }
      }  // Finish iterating over vertices
      // There should be a difference of 1 between min_time and max_time
      if (max_time - min_time != 1)
      {
        invalid++;
#ifdef DETAILED_DEBUGGING
        this_cell_foliation_valid = false;
#endif
        // Single-threaded delete max vertex
        // universe_ptr->remove(cit->vertex(max_vertex));

        // Parallel delete std::set of max_vertex for all invalid cells
        deleted_vertices.emplace(cit->vertex(max_vertex));
      }
      else
      {
        ++valid;
      }

#ifdef DETAILED_DEBUGGING
      std::cout << "Foliation for cell is "
                << ((this_cell_foliation_valid) ? "valid." : "invalid.\n");
      for (auto i = 0; i < 4; ++i)
      {
        std::cout << "Vertex " << i << " is " << cit->vertex(i)->point()
                  << " with timeslice " << cit->vertex(i)->info() << "\n";
      }
#endif
    }
    else
    {
      throw std::runtime_error("Cell handle is invalid!");
      // Or just remove the cell
      // universe_ptr->tds().delete_cell(cit);
      // This results in a possibly broken Delaunay triangulation
      // Or possibly just delete a vertex in the cell,
      // perhaps forcing a re-triangulation?
    }
  }  // Finish iterating over cells

  // Delete invalid vertices
  universe_ptr->remove(deleted_vertices.begin(), deleted_vertices.end());
  // Check that the triangulation is still valid
  // Turned off by -DCGAL_TRIANGULATION_NO_POSTCONDITIONS
  //  CGAL_triangulation_expensive_postcondition(universe_ptr->is_valid());
  if (!universe_ptr->tds().is_valid())
    throw std::logic_error("Delaunay tds invalid!");

#ifndef NDEBUG
  std::cout << "There are " << invalid << " invalid simplices and " << valid
            << " valid simplices.\n";
#endif
  return invalid == 0;
}  // fix_timeslices

/// @brief Fixes the foliation of the triangulation
///
/// Runs fix_timeslices() to fix foliation until there are no errors,
/// or MAX_FOLIATION_FIX_PASSES whichever comes first.
///
/// @param universe_ptr A std::unique_ptr<Delaunay> to the triangulation
template <typename Manifold>
void fix_triangulation(Manifold&& universe_ptr)
{
  for (std::size_t pass = 0; pass < MAX_FOLIATION_FIX_PASSES; ++pass)
  {
#ifndef NDEBUG
    std::cout << "Fix Pass #" << (pass + 1) << "\n";
#endif
    if (fix_timeslices(universe_ptr)) break;
  }
  if (!fix_timeslices(universe_ptr))
    throw std::logic_error("Delaunay triangulation not correctly foliated.");
}  // fix_triangulation()

/// @brief Inserts vertices with timeslices into Delaunay triangulation
///
/// @tparam Manifold Type of universe_ptr
/// @param universe_ptr A unique pointer to triangulation
/// @param cv A data structure of causal vertices
template <typename Manifold>
void insert_into_triangulation(Manifold&& universe_ptr, Causal_vertices cv)
{
  universe_ptr->insert(cv.begin(), cv.end());
}  // insert_into_triangulation()

/// @brief Make foliated spheres
///
/// The radius is used to denote the time value, so we can nest 2-spheres
/// such that our time foliation contains leaves of identical topology.
///
/// @param simplices The number of desired simplices in the triangulation
/// @param timeslices  The number of desired timeslices in the triangulation
/// @return A std::vector<std::pair<Point, std::size_t>> containing random
/// vertices and their corresponding timevalues
[[nodiscard]] auto inline make_foliated_sphere(
    const std::size_t simplices, const std::size_t timeslices,
    double initial_radius = INITIAL_RADIUS,
    double radial_factor  = RADIAL_FACTOR)
{
  //  double     radius{0};
  const auto points_per_timeslice =
      expected_points_per_simplex(DIMENSION, simplices, timeslices);
  CGAL_triangulation_precondition(points_per_timeslice >= 2);
  Causal_vertices causal_vertices;
  using Spherical_points_generator_3 = CGAL::Random_points_on_sphere_3<Point>;

  for (std::size_t i = 0; i < timeslices; ++i)
  {
    auto radius = initial_radius + static_cast<double>(i) * radial_factor;
    //    CGAL::Random_points_on_sphere_3<Point> gen{radius};
    Spherical_points_generator_3 gen{radius};
    // At each radius, generate a sphere of random points proportional to area
    for (std::size_t j = 0;
         j < static_cast<std::size_t>(points_per_timeslice * radius); ++j)
    { causal_vertices.emplace_back(std::make_pair(*gen++, i + 1)); }  // end j
  }                                                                   // end i
  return causal_vertices;
}  // make_foliated_sphere()

/// @brief Make a triangulation from foliated 2-spheres
///
/// This function creates a triangulation from successive spheres.
/// First, the number of points per leaf in the foliation is estimated given
/// the desired number of simplices.
/// Next, make_foliated_sphere() is called to generate nested spheres.
/// The radius of the sphere is assigned as the time value for each vertex
/// in that sphere, which comprises a leaf in the foliation.
/// All vertices in all spheres (along with their time values) are then
/// inserted with insert_into_triangulation() into a Delaunay triangulation
/// (see http://en.wikipedia.org/wiki/Delaunay_triangulation for details).
/// Finally, fix_triangulation() removes cells in the Delaunay triangulation
/// with invalid foliations using fix_timeslices(). A last check is performed
/// to ensure a valid Delaunay triangulation.
///
/// @param[in] simplices  The number of desired simplices in the triangulation
/// @param[in] timeslices The number of timeslices in the triangulation
/// @returns A std::unique_ptr<Delaunay> to the foliated triangulation
[[nodiscard]] auto inline make_triangulation(
    const std::size_t simplices, const std::size_t timeslices,
    double initial_radius = INITIAL_RADIUS,
    double radial_factor  = RADIAL_FACTOR)
{
  std::cout << "Generating universe ... \n";

#ifdef CGAL_LINKED_WITH_TBB
  // Construct the locking data-structure
  // using the bounding-box of the points
  auto bounding_box_size = static_cast<double>(timeslices + 1);
  Delaunay::Lock_data_structure locking_ds{
      CGAL::Bbox_3{-bounding_box_size, -bounding_box_size, -bounding_box_size,
                   bounding_box_size, bounding_box_size, bounding_box_size},
      50};
  Delaunay universe{K{}, &locking_ds};
#else
  Delaunay3 universe{};
#endif

  auto universe_ptr    = std::make_unique<decltype(universe)>(universe);
  auto causal_vertices = make_foliated_sphere(simplices, timeslices,
                                              initial_radius, radial_factor);
  insert_into_triangulation(universe_ptr, causal_vertices);
  fix_triangulation(universe_ptr);
  if (!universe_ptr->is_valid())
    throw std::logic_error("Delaunay triangulation invalid!");
  return universe_ptr;
}  // make_triangulation()

#endif  // INCLUDE_S3TRIANGULATION_HPP_
<|endoftext|>


<commit_before>//
// web_socket.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2013 Jack (jack at gmail dot com)
//
// Distributed under the GNU Affero General Public License, Version 3.0. (See accompanying
// file LICENSE or copy at http://www.gnu.org/licenses/agpl-3.0.txt)
//

#ifndef AVWS_WEB_SOCKET_HPP
#define AVWS_WEB_SOCKET_HPP

#include "avws.hpp"

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/noncopyable.hpp>
#include <boost/asio.hpp>
#include <boost/asio/detail/config.hpp>

namespace avws {

using boost::asio::ip::tcp;

class web_socket : public boost::noncopyable
{
public:
	// Constructor.
	AVWS_DECL explicit web_socket(boost::asio::io_service &io)
		: m_ioservice(io)
	{
	}

	// Destructor.
	AVWS_DECL virtual ~web_socket()
	{
	}

	// 设置请求选项信息, 必须在open或accept之前设置.
	AVWS_DECL void request_options(const request_opts &options);
	// 返回当前连接的请求选项.
	AVWS_DECL request_opts request_options(void) const;
	// 返回当前连接的回复选项信息.
	AVWS_DECL response_opts response_options(void) const;

	// 在open或accept的步骤里, 实行了websocket认证.

	// 打开url.
	AVWS_DECL void open(const url &u);
	AVWS_DECL void open(const url &u, boost::system::error_code &ec);

	// 异步打开url.
	template <typename Handler>
	void async_open(const url &u, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 关闭底层连接.
	AVWS_DECL void close();
	AVWS_DECL void close(boost::system::error_code &ec);

	// 在websocket中, 数据封装成frame由发送函数实现, 上层用户无需操心.
	// 至于是文本还是二进制, 由request_options确定.
	// 由于websocket是基于message设计, 所以, write_some每次实际上将
	// 是发送一条完整的消息.

	// 同步发送消息.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers);
	// 同步发送消息.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers,
		boost::system::error_code &ec);

	// 异步发送消息.
	template <typename ConstBufferSequence, typename Handler>
	void async_write_some(const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 同步接收消息.
	template <typename MutableBufferSequence>
	std::size_t read_some(const MutableBufferSequence &buffers);
	// 同步接收消息.
	template <typename MutableBufferSequence>
	std::size_t read_some(const MutableBufferSequence &buffers,
		boost::system::error_code &ec);

	// 异步接收消息.
	template <typename MutableBufferSequence, typename Handler>
	void async_read_some(const MutableBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

protected:

	boost::asio::io_service& m_ioservice;
};

} // namespace avws

#endif // AVWS_WEB_SOCKET_HPP
<commit_msg>commit websocket.open<commit_after>//
// web_socket.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2013 Jack (jack at gmail dot com)
//
// Distributed under the GNU Affero General Public License, Version 3.0. (See accompanying
// file LICENSE or copy at http://www.gnu.org/licenses/agpl-3.0.txt)
//

#ifndef AVWS_WEB_SOCKET_HPP
#define AVWS_WEB_SOCKET_HPP

#include "avws.hpp"

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/noncopyable.hpp>
#include <boost/asio.hpp>
#include <boost/asio/detail/config.hpp>

namespace avws {

using boost::asio::ip::tcp;

// 这是一个web_socket接口实现.
class web_socket : public boost::noncopyable
{
public:
	// Constructor.
	AVWS_DECL explicit web_socket(boost::asio::io_service &io)
		: m_ioservice(io)
	{
	}

	// Destructor.
	AVWS_DECL virtual ~web_socket()
	{
	}

	// 设置请求选项信息, 必须在open或accept之前设置.
	AVWS_DECL void request_options(const request_opts &options);
	// 返回当前连接的请求选项.
	AVWS_DECL request_opts request_options(void) const;
	// 返回当前连接的回复选项信息.
	AVWS_DECL response_opts response_options(void) const;

	// 在open或accept的步骤里, 实行了websocket认证.

	// 打开url.
	AVWS_DECL void open(const url &u)
	{
		boost::system::error_code ec;
		open(u, ec);
		if (ec)
		{
			boost::throw_exception(boost::system::system_error(ec));
		}
	}

	AVWS_DECL void open(const url &u, boost::system::error_code &ec)
	{
		// 保存url相关的信息.
		m_protocol = u.protocol();
		m_url = u;

		// 输出打开的链接地址.
		LOG_DEBUG("Sync open url \'" << u.to_string() << "\'");

		// 判断不支持的协议, 并返回错误.
		if (m_protocol != "ws")
		{
			LOG_ERROR("Unsupported scheme \'" << m_protocol << "\'");
			ec = boost::asio::error::operation_not_supported;
			return;
		}

	}

	// 异步打开url.
	template <typename Handler>
	void async_open(const url &u, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 关闭底层连接.
	AVWS_DECL void close();
	AVWS_DECL void close(boost::system::error_code &ec);

	// 在websocket中, 数据封装成frame由发送函数实现, 上层用户无需操心.
	// 至于是文本还是二进制, 由request_options确定.
	// 由于websocket是基于message设计, 所以, write_some每次实际上将
	// 是发送一条完整的消息.

	// 同步发送消息.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers);
	// 同步发送消息.
	template <typename ConstBufferSequence>
	std::size_t write_some(const ConstBufferSequence &buffers,
		boost::system::error_code &ec);

	// 异步发送消息.
	template <typename ConstBufferSequence, typename Handler>
	void async_write_some(const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

	// 同步接收消息.
	template <typename MutableBufferSequence>
	std::size_t read_some(const MutableBufferSequence &buffers);
	// 同步接收消息.
	template <typename MutableBufferSequence>
	std::size_t read_some(const MutableBufferSequence &buffers,
		boost::system::error_code &ec);

	// 异步接收消息.
	template <typename MutableBufferSequence, typename Handler>
	void async_read_some(const MutableBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler);

protected:

	// io_service引用, 由用户在构造时传入, 并由用户运行.
	boost::asio::io_service& m_ioservice;

	// 当前url.
	url m_url;

	// 当前协议.
	std::string m_protocol;
};

} // namespace avws

#endif // AVWS_WEB_SOCKET_HPP
<|endoftext|>


<commit_before>/*
* Copyright (c) 2014 Eran Pe'er.
*
* This program is made available under the terms of the MIT License.
*
* Created on Mar 10, 2014
*/

#ifndef MockImpl_h__
#define MockImpl_h__

#include <type_traits>
#include <unordered_set>

#include <memory>

#include "mockutils/DynamicProxy.hpp"
#include "fakeit/StubbingImpl.hpp"
#include "fakeit/DomainObjects.hpp"
#include "fakeit/FakeIt.hpp"

namespace fakeit {

	template<typename C, typename ... baseclasses>
	class MockImpl : public MockObject<C>, public virtual ActualInvocationsSource {
	public:

		MockImpl(C &obj) :MockImpl<C, baseclasses...>(obj, true) {
		}

		MockImpl() : MockImpl<C, baseclasses...>(*(createFakeInstance()), false) {
		}

		virtual ~MockImpl() {
			if (isSpy)
				return;
			FakeObject<C, baseclasses...>* fake = (FakeObject<C, baseclasses...>*) instance;
			delete fake;
		}

		/**
		* Return all actual invocations of this mock.
		*/
		void getActualInvocations(std::unordered_set<Invocation*>& into) const override {
			std::vector<ActualInvocationsSource*> vec;
			proxy.getMethodMocks(vec);
			for (ActualInvocationsSource * s : vec) {
				s->getActualInvocations(into);
			}
		}

		void reset() {
			proxy.Reset();
			if (!isSpy) {
				FakeObject<C, baseclasses...>* fake = (FakeObject<C, baseclasses...>*) instance;
				fake->initializeDataMembersArea();
			}
		}

		virtual C& get() override {
			return proxy.get();
		}

		template<class DATA_TYPE, typename ... arglist>
		DataMemberStubbingRoot<C, DATA_TYPE> stubDataMember(DATA_TYPE C::*member, const arglist&... ctorargs) {
			proxy.stubDataMember(member, ctorargs...);
			return DataMemberStubbingRoot<C, DATA_TYPE>();
		}

		template<typename R, typename ... arglist, class = typename std::enable_if<!std::is_void<R>::value>::type>
		FunctionStubbingRoot<C, R, arglist...> stub(R(C::*vMethod)(arglist...)) {
			return FunctionStubbingRoot<C, R, arglist...>(
				std::shared_ptr<MethodStubbingContext<C, R, arglist...>>(new MethodStubbingContextImpl<R, arglist...>(*this, vMethod)));
		}

		template<typename R, typename ... arglist, class = typename std::enable_if<std::is_void<R>::value>::type>
		ProcedureStubbingRoot<C, R, arglist...> stub(R(C::*vMethod)(arglist...)) {
			return ProcedureStubbingRoot<C, R, arglist...>(
				std::shared_ptr<MethodStubbingContext<C, R, arglist...>>(new MethodStubbingContextImpl<R, arglist...>(*this, vMethod)));
		}

	private:
		DynamicProxy<C, baseclasses...> proxy;
		C* instance; //
		bool isSpy;

		template<typename R, typename ... arglist>
		class MethodStubbingContextImpl : public MethodStubbingContext<C, R, arglist...> {
			MockImpl<C, baseclasses...>& mock;
			typename MethodStubbingContext<C, R, arglist...>::MethodType vMethod;
		public:

			MethodStubbingContextImpl(MockImpl<C, baseclasses...>& mock, R(C::*vMethod)(arglist...)) :
				mock(mock), vMethod(vMethod) {
			}

			virtual MethodMock<C, R, arglist...>& getMethodMock() override {
				return mock.stubMethodIfNotStubbed(mock.proxy, vMethod);
			}

			virtual void getActualInvocations(std::unordered_set<Invocation*>& into) const override {
				mock.getActualInvocations(into);
			}

			virtual typename MethodStubbingContext<C, R, arglist...>::MethodType getOriginalMethod() override {
				void * mPtr = mock.getOriginalMethod(vMethod);
				return union_cast<typename MethodStubbingContext<C, R, arglist...>::MethodType>(mPtr);
			}

			virtual MockObject<C>& getMock() override {
				return mock;
			}

		};

		void unmocked() {
			struct UnmockedMethodInvocation : public UnexpectedMethodCallException {
				UnmockedMethodInvocation() :UnexpectedMethodCallException( //
				std::shared_ptr<Invocation> {new ActualInvocation<>(nextInvocationOrdinal(), UnknownMethod::instance())} //
				){} //
			} e;
			FakeIt::getInstance().handle(e);
			throw e;
		}

		static C* createFakeInstance() {
			FakeObject<C, baseclasses...>* fake = new FakeObject<C, baseclasses...>();
			fake->initializeDataMembersArea();
			void* unmockedMethodStubPtr = union_cast<void*>(&MockImpl<C, baseclasses...>::unmocked);
			fake->getVirtualTable().initAll(unmockedMethodStubPtr);
			return (C*) fake;
		}

		template<typename R, typename ... arglist>
		void * getOriginalMethod(R(C::*vMethod)(arglist...)) {
			auto vt = proxy.getOriginalVT();
			auto offset = VTUtils::getOffset(vMethod);
			void * origMethodPtr = vt.getMethod(offset);
			return origMethodPtr;
		}

		template<typename R, typename ... arglist>
		MethodMock<C, R, arglist...>& stubMethodIfNotStubbed(DynamicProxy<C, baseclasses...> &proxy, R(C::*vMethod)(arglist...)) {
			if (!proxy.isStubbed(vMethod)) {
				auto methodMock = std::shared_ptr<MethodInvocationHandler<R, arglist...>> { new MethodMock<C, R, arglist...>(*this, vMethod) };
				proxy.stubMethod(vMethod, methodMock);
			}
			Destructable * d = proxy.getMethodMock(vMethod);
			MethodMock<C, R, arglist...> * methodMock = dynamic_cast<MethodMock<C, R, arglist...> *>(d);
			return *methodMock;
		}

		MockImpl(C &obj, bool isSpy) :
			proxy{ obj }, instance(&obj), isSpy(isSpy) {
		}
	};
}

#endif<commit_msg>fix data members names<commit_after>/*
* Copyright (c) 2014 Eran Pe'er.
*
* This program is made available under the terms of the MIT License.
*
* Created on Mar 10, 2014
*/

#ifndef MockImpl_h__
#define MockImpl_h__

#include <type_traits>
#include <unordered_set>

#include <memory>

#include "mockutils/DynamicProxy.hpp"
#include "fakeit/StubbingImpl.hpp"
#include "fakeit/DomainObjects.hpp"
#include "fakeit/FakeIt.hpp"

namespace fakeit {

	template<typename C, typename ... baseclasses>
	class MockImpl : public MockObject<C>, public virtual ActualInvocationsSource {
	public:

		MockImpl(C &obj) :MockImpl<C, baseclasses...>(obj, true) {
		}

		MockImpl() : MockImpl<C, baseclasses...>(*(createFakeInstance()), false) {
		}

		virtual ~MockImpl() {
			if (_isSpy)
				return;
			FakeObject<C, baseclasses...>* fake = (FakeObject<C, baseclasses...>*) _instance;
			delete fake;
		}

		/**
		* Return all actual invocations of this mock.
		*/
		void getActualInvocations(std::unordered_set<Invocation*>& into) const override {
			std::vector<ActualInvocationsSource*> vec;
			_proxy.getMethodMocks(vec);
			for (ActualInvocationsSource * s : vec) {
				s->getActualInvocations(into);
			}
		}

		void reset() {
			_proxy.Reset();
			if (!_isSpy) {
				FakeObject<C, baseclasses...>* fake = (FakeObject<C, baseclasses...>*) _instance;
				fake->initializeDataMembersArea();
			}
		}

		virtual C& get() override {
			return _proxy.get();
		}

		template<class DATA_TYPE, typename ... arglist>
		DataMemberStubbingRoot<C, DATA_TYPE> stubDataMember(DATA_TYPE C::*member, const arglist&... ctorargs) {
			_proxy.stubDataMember(member, ctorargs...);
			return DataMemberStubbingRoot<C, DATA_TYPE>();
		}

		template<typename R, typename ... arglist, class = typename std::enable_if<!std::is_void<R>::value>::type>
		FunctionStubbingRoot<C, R, arglist...> stub(R(C::*vMethod)(arglist...)) {
			return FunctionStubbingRoot<C, R, arglist...>(
				std::shared_ptr<MethodStubbingContext<C, R, arglist...>>(new MethodStubbingContextImpl<R, arglist...>(*this, vMethod)));
		}

		template<typename R, typename ... arglist, class = typename std::enable_if<std::is_void<R>::value>::type>
		ProcedureStubbingRoot<C, R, arglist...> stub(R(C::*vMethod)(arglist...)) {
			return ProcedureStubbingRoot<C, R, arglist...>(
				std::shared_ptr<MethodStubbingContext<C, R, arglist...>>(new MethodStubbingContextImpl<R, arglist...>(*this, vMethod)));
		}

	private:
		DynamicProxy<C, baseclasses...> _proxy;
		C* _instance; //
		bool _isSpy;

		template<typename R, typename ... arglist>
		class MethodStubbingContextImpl : public MethodStubbingContext<C, R, arglist...> {
			MockImpl<C, baseclasses...>& mock;
			typename MethodStubbingContext<C, R, arglist...>::MethodType vMethod;
		public:

			MethodStubbingContextImpl(MockImpl<C, baseclasses...>& mock, R(C::*vMethod)(arglist...)) :
				mock(mock), vMethod(vMethod) {
			}

			virtual MethodMock<C, R, arglist...>& getMethodMock() override {
				return mock.stubMethodIfNotStubbed(mock._proxy, vMethod);
			}

			virtual void getActualInvocations(std::unordered_set<Invocation*>& into) const override {
				mock.getActualInvocations(into);
			}

			virtual typename MethodStubbingContext<C, R, arglist...>::MethodType getOriginalMethod() override {
				void * mPtr = mock.getOriginalMethod(vMethod);
				return union_cast<typename MethodStubbingContext<C, R, arglist...>::MethodType>(mPtr);
			}

			virtual MockObject<C>& getMock() override {
				return mock;
			}

		};

		void unmocked() {
			struct UnmockedMethodInvocation : public UnexpectedMethodCallException {
				UnmockedMethodInvocation() :UnexpectedMethodCallException( //
				std::shared_ptr<Invocation> {new ActualInvocation<>(nextInvocationOrdinal(), UnknownMethod::instance())} //
				){} //
			} e;
			FakeIt::getInstance().handle(e);
			throw e;
		}

		static C* createFakeInstance() {
			FakeObject<C, baseclasses...>* fake = new FakeObject<C, baseclasses...>();
			fake->initializeDataMembersArea();
			void* unmockedMethodStubPtr = union_cast<void*>(&MockImpl<C, baseclasses...>::unmocked);
			fake->getVirtualTable().initAll(unmockedMethodStubPtr);
			return (C*) fake;
		}

		template<typename R, typename ... arglist>
		void * getOriginalMethod(R(C::*vMethod)(arglist...)) {
			auto vt = _proxy.getOriginalVT();
			auto offset = VTUtils::getOffset(vMethod);
			void * origMethodPtr = vt.getMethod(offset);
			return origMethodPtr;
		}

		template<typename R, typename ... arglist>
		MethodMock<C, R, arglist...>& stubMethodIfNotStubbed(DynamicProxy<C, baseclasses...> &proxy, R(C::*vMethod)(arglist...)) {
			if (!proxy.isStubbed(vMethod)) {
				auto methodMock = std::shared_ptr<MethodInvocationHandler<R, arglist...>> { new MethodMock<C, R, arglist...>(*this, vMethod) };
				proxy.stubMethod(vMethod, methodMock);
			}
			Destructable * d = proxy.getMethodMock(vMethod);
			MethodMock<C, R, arglist...> * methodMock = dynamic_cast<MethodMock<C, R, arglist...> *>(d);
			return *methodMock;
		}

		MockImpl(C &obj, bool isSpy) :
			_proxy{ obj }, _instance(&obj), _isSpy(isSpy) {
		}
	};
}

#endif<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef FORMULA_GRAMMAR_HXX
#define FORMULA_GRAMMAR_HXX

#include "com/sun/star/sheet/FormulaLanguage.hpp"
#include "formula/formuladllapi.h"
#include <tools/debug.hxx>

namespace formula
{

/** Grammars digested by ScCompiler.
 */
class FORMULA_DLLPUBLIC FormulaGrammar
{
public:
    enum AddressConvention{
        CONV_UNSPECIFIED = -1,  /* useful when we want method to chose, must be first */

        /* elements must be sequential and changes should be reflected in ScCompiler::pCharTables */
        CONV_OOO     =  0,  /* 'doc'#sheet.A1:sheet2.B2 */
        CONV_ODF,           /* ['doc'#sheet.A1:sheet2.B2] */
        CONV_XL_A1,         /* [doc]sheet:sheet2!A1:B2 */
        CONV_XL_R1C1,       /* [doc]sheet:sheet2!R1C1:R2C2 */
        CONV_XL_OOX,        /* [#]sheet:sheet2!A1:B2 */

        CONV_LOTUS_A1,      /* external? 3d? A1.B2 <placeholder/> */

        CONV_LAST   /* for loops, must always be last */
    };

    //! CONV_UNSPECIFIED is a negative value!
    static const int kConventionOffset = - CONV_UNSPECIFIED + 1;
    // Room for 32k hypothetical languages plus EXTERNAL.
    static const int kConventionShift  = 16;
    // Room for 256 reference conventions.
    static const int kEnglishBit       = (1 << (kConventionShift + 8));
    // Mask off all non-language bits.
    static const int kFlagMask         = ~((~int(0)) << kConventionShift);

    /** Values encoding the formula language plus address reference convention
        plus English parsing/formatting
     */
    //! When adding new values adapt isSupported() below as well.
    enum Grammar
    {
        /// Used only in ScCompiler ctor and in some XML import API context.
        GRAM_UNSPECIFIED    = -1,
        /// ODFF with default ODF A1 bracketed references.
        GRAM_ODFF           = ::com::sun::star::sheet::FormulaLanguage::ODFF    |
                                ((CONV_ODF           +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// ODF 1.1 with default ODF A1 bracketed references.
        GRAM_PODF           = ::com::sun::star::sheet::FormulaLanguage::ODF_11  |
                                ((CONV_ODF           +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// English with default A1 reference style.
        GRAM_ENGLISH        = ::com::sun::star::sheet::FormulaLanguage::ENGLISH |
                                ((CONV_OOO           +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// Native with default A1 reference style.
        GRAM_NATIVE         = ::com::sun::star::sheet::FormulaLanguage::NATIVE  |
                                ((CONV_OOO           +
                                  kConventionOffset) << kConventionShift),
        /// ODFF with reference style as set in UI, may be A1 or R1C1.
        GRAM_ODFF_UI        = ::com::sun::star::sheet::FormulaLanguage::ODFF    |
                                ((CONV_UNSPECIFIED   +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// ODFF with A1 reference style, unbracketed.
        GRAM_ODFF_A1        = ::com::sun::star::sheet::FormulaLanguage::ODFF    |
                                ((CONV_OOO           +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// ODF 1.1 with reference style as set in UI, may be A1 or R1C1.
        GRAM_PODF_UI        = ::com::sun::star::sheet::FormulaLanguage::ODF_11  |
                                ((CONV_UNSPECIFIED   +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// ODF 1.1 with A1 reference style, unbracketed.
        GRAM_PODF_A1        = ::com::sun::star::sheet::FormulaLanguage::ODF_11  |
                                ((CONV_OOO           +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// Native with reference style as set in UI, may be A1 or R1C1.
        GRAM_NATIVE_UI      = ::com::sun::star::sheet::FormulaLanguage::NATIVE  |
                                ((CONV_UNSPECIFIED   +
                                  kConventionOffset) << kConventionShift),
        /// Native with ODF A1 bracketed references. Not very useful but supported.
        GRAM_NATIVE_ODF     = ::com::sun::star::sheet::FormulaLanguage::NATIVE  |
                                ((CONV_ODF           +
                                  kConventionOffset) << kConventionShift),
        /// Native with Excel A1 reference style.
        GRAM_NATIVE_XL_A1   = ::com::sun::star::sheet::FormulaLanguage::NATIVE  |
                                ((CONV_XL_A1         +
                                  kConventionOffset) << kConventionShift),
        /// Native with Excel R1C1 reference style.
        GRAM_NATIVE_XL_R1C1 = ::com::sun::star::sheet::FormulaLanguage::NATIVE  |
                                ((CONV_XL_R1C1       +
                                  kConventionOffset) << kConventionShift),
        /// English with Excel A1 reference style.
        GRAM_ENGLISH_XL_A1   = ::com::sun::star::sheet::FormulaLanguage::XL_ENGLISH  |
                                ((CONV_XL_A1         +
                                  kConventionOffset) << kConventionShift)            |
                                kEnglishBit,
        /// English with Excel R1C1 reference style.
        GRAM_ENGLISH_XL_R1C1 = ::com::sun::star::sheet::FormulaLanguage::XL_ENGLISH  |
                                ((CONV_XL_R1C1       +
                                  kConventionOffset) << kConventionShift)            |
                                kEnglishBit,
        /// English with Excel OOXML reference style.
        GRAM_ENGLISH_XL_OOX  = ::com::sun::star::sheet::FormulaLanguage::XL_ENGLISH  |
                                ((CONV_XL_OOX        +
                                  kConventionOffset) << kConventionShift)            |
                                kEnglishBit,
        /// Central definition of the default grammar to be used.
        GRAM_DEFAULT        = GRAM_NATIVE_UI,

        /// Central definition of the default storage grammar to be used.
        GRAM_STORAGE_DEFAULT = GRAM_ODFF,

        /** OpCodeMap set by external filter and merged with reference
            convention plus English bit on top. Plain value acts as
            FormulaLanguage. */
        GRAM_EXTERNAL       = (1 << (kConventionShift - 1))
    };

    /// If English parsing/formatting is associated with a grammar.
    static inline bool isEnglish( const Grammar eGrammar )
    {
        return (eGrammar & kEnglishBit) != 0;
    }

    /** Compatibility helper for old "bCompileEnglish, bCompileXML" API calls
        to obtain the new grammar. */
    static Grammar mapAPItoGrammar( const bool bEnglish, const bool bXML )
    {
        Grammar eGrammar;
        if (bEnglish && bXML)
            eGrammar = GRAM_PODF;
        else if (bEnglish && !bXML)
            eGrammar = GRAM_PODF_A1;
        else if (!bEnglish && bXML)
            eGrammar = GRAM_NATIVE_ODF;
        else // (!bEnglish && !bXML)
            eGrammar = GRAM_NATIVE;
        return eGrammar;
    }

    static bool isSupported( const Grammar eGrammar )
    {
        switch (eGrammar)
        {
            case GRAM_ODFF           :
            case GRAM_PODF           :
            case GRAM_ENGLISH        :
            case GRAM_NATIVE         :
            case GRAM_ODFF_UI        :
            case GRAM_ODFF_A1        :
            case GRAM_PODF_UI        :
            case GRAM_PODF_A1        :
            case GRAM_NATIVE_UI      :
            case GRAM_NATIVE_ODF     :
            case GRAM_NATIVE_XL_A1   :
            case GRAM_NATIVE_XL_R1C1 :
            case GRAM_ENGLISH_XL_A1  :
            case GRAM_ENGLISH_XL_R1C1:
                return true;
            default:
                return extractFormulaLanguage( eGrammar) == GRAM_EXTERNAL;
        }
    }

    static inline sal_Int32 extractFormulaLanguage( const Grammar eGrammar )
    {
        return eGrammar & kFlagMask;
    }

    static inline AddressConvention extractRefConvention( const Grammar eGrammar )
    {
        return static_cast<AddressConvention>(
                ((eGrammar & ~kEnglishBit) >> kConventionShift) -
                kConventionOffset);
    }

    static inline Grammar setEnglishBit( const Grammar eGrammar, const bool bEnglish )
    {
        if (bEnglish)
            return static_cast<Grammar>( eGrammar | kEnglishBit);
        else
            return static_cast<Grammar>( eGrammar & ~kEnglishBit);
    }

    static inline Grammar mergeToGrammar( const Grammar eGrammar, const AddressConvention eConv )
    {
        bool bEnglish = isEnglish( eGrammar);
        Grammar eGram = static_cast<Grammar>(
                extractFormulaLanguage( eGrammar) |
                ((eConv + kConventionOffset) << kConventionShift));
        eGram = setEnglishBit( eGram, bEnglish);
        DBG_ASSERT( isSupported( eGram), "CompilerGrammarMap::mergeToGrammar: unsupported grammar");
        return eGram;
    }

    /// If grammar is of ODF 1.1
    static inline bool isPODF( const Grammar eGrammar )
    {
        return extractFormulaLanguage( eGrammar) ==
            ::com::sun::star::sheet::FormulaLanguage::ODF_11;
    }

    /// If grammar is of ODFF
    static inline bool isODFF( const Grammar eGrammar )
    {
        return extractFormulaLanguage( eGrammar) ==
            ::com::sun::star::sheet::FormulaLanguage::ODFF;
    }

};
// =============================================================================
} // formula
// =============================================================================

#endif // FORMULA_GRAMMAR_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Add GRAM_ENGLISH_XL_OOX as supported<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef FORMULA_GRAMMAR_HXX
#define FORMULA_GRAMMAR_HXX

#include "com/sun/star/sheet/FormulaLanguage.hpp"
#include "formula/formuladllapi.h"
#include <tools/debug.hxx>

namespace formula
{

/** Grammars digested by ScCompiler.
 */
class FORMULA_DLLPUBLIC FormulaGrammar
{
public:
    enum AddressConvention{
        CONV_UNSPECIFIED = -1,  /* useful when we want method to chose, must be first */

        /* elements must be sequential and changes should be reflected in ScCompiler::pCharTables */
        CONV_OOO     =  0,  /* 'doc'#sheet.A1:sheet2.B2 */
        CONV_ODF,           /* ['doc'#sheet.A1:sheet2.B2] */
        CONV_XL_A1,         /* [doc]sheet:sheet2!A1:B2 */
        CONV_XL_R1C1,       /* [doc]sheet:sheet2!R1C1:R2C2 */
        CONV_XL_OOX,        /* [#]sheet:sheet2!A1:B2 */

        CONV_LOTUS_A1,      /* external? 3d? A1.B2 <placeholder/> */

        CONV_LAST   /* for loops, must always be last */
    };

    //! CONV_UNSPECIFIED is a negative value!
    static const int kConventionOffset = - CONV_UNSPECIFIED + 1;
    // Room for 32k hypothetical languages plus EXTERNAL.
    static const int kConventionShift  = 16;
    // Room for 256 reference conventions.
    static const int kEnglishBit       = (1 << (kConventionShift + 8));
    // Mask off all non-language bits.
    static const int kFlagMask         = ~((~int(0)) << kConventionShift);

    /** Values encoding the formula language plus address reference convention
        plus English parsing/formatting
     */
    //! When adding new values adapt isSupported() below as well.
    enum Grammar
    {
        /// Used only in ScCompiler ctor and in some XML import API context.
        GRAM_UNSPECIFIED    = -1,
        /// ODFF with default ODF A1 bracketed references.
        GRAM_ODFF           = ::com::sun::star::sheet::FormulaLanguage::ODFF    |
                                ((CONV_ODF           +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// ODF 1.1 with default ODF A1 bracketed references.
        GRAM_PODF           = ::com::sun::star::sheet::FormulaLanguage::ODF_11  |
                                ((CONV_ODF           +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// English with default A1 reference style.
        GRAM_ENGLISH        = ::com::sun::star::sheet::FormulaLanguage::ENGLISH |
                                ((CONV_OOO           +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// Native with default A1 reference style.
        GRAM_NATIVE         = ::com::sun::star::sheet::FormulaLanguage::NATIVE  |
                                ((CONV_OOO           +
                                  kConventionOffset) << kConventionShift),
        /// ODFF with reference style as set in UI, may be A1 or R1C1.
        GRAM_ODFF_UI        = ::com::sun::star::sheet::FormulaLanguage::ODFF    |
                                ((CONV_UNSPECIFIED   +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// ODFF with A1 reference style, unbracketed.
        GRAM_ODFF_A1        = ::com::sun::star::sheet::FormulaLanguage::ODFF    |
                                ((CONV_OOO           +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// ODF 1.1 with reference style as set in UI, may be A1 or R1C1.
        GRAM_PODF_UI        = ::com::sun::star::sheet::FormulaLanguage::ODF_11  |
                                ((CONV_UNSPECIFIED   +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// ODF 1.1 with A1 reference style, unbracketed.
        GRAM_PODF_A1        = ::com::sun::star::sheet::FormulaLanguage::ODF_11  |
                                ((CONV_OOO           +
                                  kConventionOffset) << kConventionShift)       |
                                kEnglishBit,
        /// Native with reference style as set in UI, may be A1 or R1C1.
        GRAM_NATIVE_UI      = ::com::sun::star::sheet::FormulaLanguage::NATIVE  |
                                ((CONV_UNSPECIFIED   +
                                  kConventionOffset) << kConventionShift),
        /// Native with ODF A1 bracketed references. Not very useful but supported.
        GRAM_NATIVE_ODF     = ::com::sun::star::sheet::FormulaLanguage::NATIVE  |
                                ((CONV_ODF           +
                                  kConventionOffset) << kConventionShift),
        /// Native with Excel A1 reference style.
        GRAM_NATIVE_XL_A1   = ::com::sun::star::sheet::FormulaLanguage::NATIVE  |
                                ((CONV_XL_A1         +
                                  kConventionOffset) << kConventionShift),
        /// Native with Excel R1C1 reference style.
        GRAM_NATIVE_XL_R1C1 = ::com::sun::star::sheet::FormulaLanguage::NATIVE  |
                                ((CONV_XL_R1C1       +
                                  kConventionOffset) << kConventionShift),
        /// English with Excel A1 reference style.
        GRAM_ENGLISH_XL_A1   = ::com::sun::star::sheet::FormulaLanguage::XL_ENGLISH  |
                                ((CONV_XL_A1         +
                                  kConventionOffset) << kConventionShift)            |
                                kEnglishBit,
        /// English with Excel R1C1 reference style.
        GRAM_ENGLISH_XL_R1C1 = ::com::sun::star::sheet::FormulaLanguage::XL_ENGLISH  |
                                ((CONV_XL_R1C1       +
                                  kConventionOffset) << kConventionShift)            |
                                kEnglishBit,
        /// English with Excel OOXML reference style.
        GRAM_ENGLISH_XL_OOX  = ::com::sun::star::sheet::FormulaLanguage::XL_ENGLISH  |
                                ((CONV_XL_OOX        +
                                  kConventionOffset) << kConventionShift)            |
                                kEnglishBit,
        /// Central definition of the default grammar to be used.
        GRAM_DEFAULT        = GRAM_NATIVE_UI,

        /// Central definition of the default storage grammar to be used.
        GRAM_STORAGE_DEFAULT = GRAM_ODFF,

        /** OpCodeMap set by external filter and merged with reference
            convention plus English bit on top. Plain value acts as
            FormulaLanguage. */
        GRAM_EXTERNAL       = (1 << (kConventionShift - 1))
    };

    /// If English parsing/formatting is associated with a grammar.
    static inline bool isEnglish( const Grammar eGrammar )
    {
        return (eGrammar & kEnglishBit) != 0;
    }

    /** Compatibility helper for old "bCompileEnglish, bCompileXML" API calls
        to obtain the new grammar. */
    static Grammar mapAPItoGrammar( const bool bEnglish, const bool bXML )
    {
        Grammar eGrammar;
        if (bEnglish && bXML)
            eGrammar = GRAM_PODF;
        else if (bEnglish && !bXML)
            eGrammar = GRAM_PODF_A1;
        else if (!bEnglish && bXML)
            eGrammar = GRAM_NATIVE_ODF;
        else // (!bEnglish && !bXML)
            eGrammar = GRAM_NATIVE;
        return eGrammar;
    }

    static bool isSupported( const Grammar eGrammar )
    {
        switch (eGrammar)
        {
            case GRAM_ODFF           :
            case GRAM_PODF           :
            case GRAM_ENGLISH        :
            case GRAM_NATIVE         :
            case GRAM_ODFF_UI        :
            case GRAM_ODFF_A1        :
            case GRAM_PODF_UI        :
            case GRAM_PODF_A1        :
            case GRAM_NATIVE_UI      :
            case GRAM_NATIVE_ODF     :
            case GRAM_NATIVE_XL_A1   :
            case GRAM_NATIVE_XL_R1C1 :
            case GRAM_ENGLISH_XL_A1  :
            case GRAM_ENGLISH_XL_R1C1:
            case GRAM_ENGLISH_XL_OOX :
                return true;
            default:
                return extractFormulaLanguage( eGrammar) == GRAM_EXTERNAL;
        }
    }

    static inline sal_Int32 extractFormulaLanguage( const Grammar eGrammar )
    {
        return eGrammar & kFlagMask;
    }

    static inline AddressConvention extractRefConvention( const Grammar eGrammar )
    {
        return static_cast<AddressConvention>(
                ((eGrammar & ~kEnglishBit) >> kConventionShift) -
                kConventionOffset);
    }

    static inline Grammar setEnglishBit( const Grammar eGrammar, const bool bEnglish )
    {
        if (bEnglish)
            return static_cast<Grammar>( eGrammar | kEnglishBit);
        else
            return static_cast<Grammar>( eGrammar & ~kEnglishBit);
    }

    static inline Grammar mergeToGrammar( const Grammar eGrammar, const AddressConvention eConv )
    {
        bool bEnglish = isEnglish( eGrammar);
        Grammar eGram = static_cast<Grammar>(
                extractFormulaLanguage( eGrammar) |
                ((eConv + kConventionOffset) << kConventionShift));
        eGram = setEnglishBit( eGram, bEnglish);
        DBG_ASSERT( isSupported( eGram), "CompilerGrammarMap::mergeToGrammar: unsupported grammar");
        return eGram;
    }

    /// If grammar is of ODF 1.1
    static inline bool isPODF( const Grammar eGrammar )
    {
        return extractFormulaLanguage( eGrammar) ==
            ::com::sun::star::sheet::FormulaLanguage::ODF_11;
    }

    /// If grammar is of ODFF
    static inline bool isODFF( const Grammar eGrammar )
    {
        return extractFormulaLanguage( eGrammar) ==
            ::com::sun::star::sheet::FormulaLanguage::ODFF;
    }

};
// =============================================================================
} // formula
// =============================================================================

#endif // FORMULA_GRAMMAR_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/*
 * Copyright 2010 2011 2012 2014 Helge Bahmann <hcb@chaoticmind.net>
 * Copyright 2011 2012 2013 2014 2015 2016 Nico Reißmann <nico.reissmann@gmail.com>
 * See COPYING for terms of redistribution.
 */

#ifndef JIVE_RVSDG_NODE_HPP
#define JIVE_RVSDG_NODE_HPP

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <unordered_set>
#include <utility>

#include <jive/rvsdg/operation.hpp>
#include <jive/rvsdg/resource.hpp>
#include <jive/util/intrusive-list.hpp>
#include <jive/util/strfmt.hpp>

namespace jive {
namespace base {
	class type;
}

class graph;
class node_normal_form;
class output;
class substitution_map;

/* inputs */

class input {
	friend jive::node;
	friend jive::region;

public:
	virtual
	~input() noexcept;

	input(
		jive::output * origin,
		jive::region * region,
		const jive::port & port);

	input(const input &) = delete;

	input(input &&) = delete;

	input &
	operator=(const input &) = delete;

	input &
	operator=(input &&) = delete;

	inline size_t
	index() const noexcept
	{
		return index_;
	}

	jive::output *
	origin() const noexcept
	{
		return origin_;
	}

	void
	divert_to(jive::output * new_origin);

	inline const jive::type &
	type() const noexcept
	{
		return port_->type();
	}

	inline jive::region *
	region() const noexcept
	{
		return region_;
	}

	inline const jive::port &
	port() const noexcept
	{
		return *port_;
	}

	virtual jive::node *
	node() const noexcept = 0;

	virtual std::string
	debug_string() const;

	inline void
	replace(const jive::port & port)
	{
		if (port_->type() != port.type())
			throw type_error(port_->type().debug_string(), port.type().debug_string());

		port_ = port.copy();
	}

private:
	size_t index_;
	jive::output * origin_;
	jive::region * region_;
	std::unique_ptr<jive::port> port_;
};

/* outputs */

class output {
	friend input;
	friend jive::node;
	friend jive::region;

	typedef std::unordered_set<jive::input*>::const_iterator user_iterator;
public:
	virtual
	~output() noexcept;

	output(
		jive::region * region,
		const jive::port & port);

	output(const output &) = delete;

	output(output &&) = delete;

	output &
	operator=(const output &) = delete;

	output &
	operator=(output &&) = delete;

	inline size_t
	index() const noexcept
	{
		return index_;
	}

	inline size_t
	nusers() const noexcept
	{
		return users_.size();
	}

	inline void
	divert_users(jive::output * new_origin)
	{
		if (this == new_origin)
			return;

		while (users_.size())
			(*users_.begin())->divert_to(new_origin);
	}

	inline user_iterator
	begin() const noexcept
	{
		return users_.begin();
	}

	inline user_iterator
	end() const noexcept
	{
		return users_.end();
	}

	inline const jive::type &
	type() const noexcept
	{
		return port_->type();
	}

	inline jive::region *
	region() const noexcept
	{
		return region_;
	}

	inline const jive::port &
	port() const noexcept
	{
		return *port_;
	}

	virtual jive::node *
	node() const noexcept = 0;

	virtual std::string
	debug_string() const;

	inline void
	replace(const jive::port & port)
	{
		if (port_->type() != port.type())
			throw type_error(port_->type().debug_string(), port.type().debug_string());

		port_ = port.copy();
	}

private:
	void
	remove_user(jive::input * user);

	void
	add_user(jive::input * user);

	size_t index_;
	jive::region * region_;
	std::unique_ptr<jive::port> port_;
	std::unordered_set<jive::input*> users_;
};

/* node_input class */

class node_input : public jive::input {
public:
	node_input(
		jive::output * origin,
		jive::node * node,
		const jive::port & port);

	virtual jive::node *
	node() const noexcept override;

private:
	jive::node * node_;
};

/* node_output class */

class node_output : public jive::output {
public:
	node_output(
		jive::node * node,
		const jive::port & port);

	jive::node *
	node() const noexcept override;

private:
	jive::node * node_;
};

/* node class */

class node {
public:
	virtual
	~node();

	node(std::unique_ptr<jive::operation> op, jive::region * region);

	inline const jive::operation &
	operation() const noexcept
	{
		return *operation_;
	}

	inline bool
	has_users() const noexcept
	{
		for (const auto & output : outputs_) {
			if (output->nusers() != 0)
				return true;
		}

		return false;
	}

	inline bool
	has_predecessors() const noexcept
	{
		for (const auto & input : inputs_) {
			if (input->origin()->node())
				return true;
		}

		return false;
	}

	inline bool
	has_successors() const noexcept
	{
		for (const auto & output : outputs_) {
			for (const auto & user : *output) {
				if (user->node())
					return true;
			}
		}

		return false;
	}

	inline size_t
	ninputs() const noexcept
	{
		return inputs_.size();
	}

	node_input *
	input(size_t index) const noexcept
	{
		JIVE_DEBUG_ASSERT(index < ninputs());
		return inputs_[index].get();
	}

	inline size_t
	noutputs() const noexcept
	{
		return outputs_.size();
	}

	node_output *
	output(size_t index) const noexcept
	{
		JIVE_DEBUG_ASSERT(index < noutputs());
		return outputs_[index].get();
	}

	inline void
	recompute_depth() noexcept;

protected:
	node_input *
	add_input(std::unique_ptr<node_input> input);

	void
	remove_input(size_t index);

	node_output *
	add_output(std::unique_ptr<node_output> output)
	{
		output->index_ = noutputs();
		outputs_.push_back(std::move(output));
		return this->output(noutputs()-1);
	}

	void
	remove_output(size_t index);

public:
	inline jive::graph *
	graph() const noexcept
	{
		return graph_;
	}

	inline jive::region *
	region() const noexcept
	{
		return region_;
	}

	virtual jive::node *
	copy(jive::region * region, const std::vector<jive::output*> & operands) const;

	/**
		\brief Copy a node with substitutions
		\param self Node to be copied
		\param target Target region to create node in
		\param substitution Operand substitutions
		\return Copied node

		Create a new node that is semantically equivalent to an
		existing node. The newly created node will use the same
		operands as the existing node unless there is a substitution
		registered for a particular operand.

		The given substitution map is updated so that all
		outputs of the original node will be substituted by
		corresponding outputs of the newly created node in
		subsequent \ref copy operations.
	*/
	virtual jive::node *
	copy(jive::region * region, jive::substitution_map & smap) const = 0;

	inline size_t
	depth() const noexcept
	{
		return depth_;
	}

private:
	jive::detail::intrusive_list_anchor<
		jive::node
	> region_node_list_anchor_;

	jive::detail::intrusive_list_anchor<
		jive::node
	> region_top_node_list_anchor_;

	jive::detail::intrusive_list_anchor<
		jive::node
	> region_bottom_node_list_anchor_;

public:
	typedef jive::detail::intrusive_list_accessor<
		jive::node,
		&jive::node::region_node_list_anchor_
	> region_node_list_accessor;

	typedef jive::detail::intrusive_list_accessor<
		jive::node,
		&jive::node::region_top_node_list_anchor_
	> region_top_node_list_accessor;

	typedef jive::detail::intrusive_list_accessor<
		jive::node,
		&jive::node::region_bottom_node_list_anchor_
	> region_bottom_node_list_accessor;

private:
	size_t depth_;
	jive::graph * graph_;
	jive::region * region_;
	std::unique_ptr<jive::operation> operation_;
	std::vector<std::unique_ptr<node_input>> inputs_;
	std::vector<std::unique_ptr<node_output>> outputs_;
};

static inline std::vector<jive::output*>
operands(const jive::node * node)
{
	std::vector<jive::output*> operands;
	for (size_t n = 0; n < node->ninputs(); n++)
		operands.push_back(node->input(n)->origin());
	return operands;
}

static inline std::vector<jive::output*>
outputs(const jive::node * node)
{
	std::vector<jive::output*> outputs;
	for (size_t n = 0; n < node->noutputs(); n++)
		outputs.push_back(node->output(n));
	return outputs;
}

static inline void
divert_users(
	jive::node * node,
	const std::vector<jive::output*> & outputs)
{
	JIVE_DEBUG_ASSERT(node->noutputs() == outputs.size());

	for (size_t n = 0; n < outputs.size(); n++)
		node->output(n)->divert_users(outputs[n]);
}

template <class T> static inline bool
is(const jive::node * node) noexcept
{
	if (!node)
		return false;

	return is<T>(node->operation());
}

jive::node *
producer(const jive::output * output) noexcept;

bool
normalize(jive::node * node);

}

#endif
<commit_msg>rvsdg: add is function for inputs<commit_after>/*
 * Copyright 2010 2011 2012 2014 Helge Bahmann <hcb@chaoticmind.net>
 * Copyright 2011 2012 2013 2014 2015 2016 Nico Reißmann <nico.reissmann@gmail.com>
 * See COPYING for terms of redistribution.
 */

#ifndef JIVE_RVSDG_NODE_HPP
#define JIVE_RVSDG_NODE_HPP

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <unordered_set>
#include <utility>

#include <jive/rvsdg/operation.hpp>
#include <jive/rvsdg/resource.hpp>
#include <jive/util/intrusive-list.hpp>
#include <jive/util/strfmt.hpp>

namespace jive {
namespace base {
	class type;
}

class graph;
class node_normal_form;
class output;
class substitution_map;

/* inputs */

class input {
	friend jive::node;
	friend jive::region;

public:
	virtual
	~input() noexcept;

	input(
		jive::output * origin,
		jive::region * region,
		const jive::port & port);

	input(const input &) = delete;

	input(input &&) = delete;

	input &
	operator=(const input &) = delete;

	input &
	operator=(input &&) = delete;

	inline size_t
	index() const noexcept
	{
		return index_;
	}

	jive::output *
	origin() const noexcept
	{
		return origin_;
	}

	void
	divert_to(jive::output * new_origin);

	inline const jive::type &
	type() const noexcept
	{
		return port_->type();
	}

	inline jive::region *
	region() const noexcept
	{
		return region_;
	}

	inline const jive::port &
	port() const noexcept
	{
		return *port_;
	}

	virtual jive::node *
	node() const noexcept = 0;

	virtual std::string
	debug_string() const;

	inline void
	replace(const jive::port & port)
	{
		if (port_->type() != port.type())
			throw type_error(port_->type().debug_string(), port.type().debug_string());

		port_ = port.copy();
	}

private:
	size_t index_;
	jive::output * origin_;
	jive::region * region_;
	std::unique_ptr<jive::port> port_;
};

template <class T> static inline bool
is(const jive::input & input) noexcept
{
	static_assert(std::is_base_of<jive::input, T>::value,
		"Template parameter T must be derived from jive::input.");

	return dynamic_cast<const T*>(&input) != nullptr;
}

/* outputs */

class output {
	friend input;
	friend jive::node;
	friend jive::region;

	typedef std::unordered_set<jive::input*>::const_iterator user_iterator;
public:
	virtual
	~output() noexcept;

	output(
		jive::region * region,
		const jive::port & port);

	output(const output &) = delete;

	output(output &&) = delete;

	output &
	operator=(const output &) = delete;

	output &
	operator=(output &&) = delete;

	inline size_t
	index() const noexcept
	{
		return index_;
	}

	inline size_t
	nusers() const noexcept
	{
		return users_.size();
	}

	inline void
	divert_users(jive::output * new_origin)
	{
		if (this == new_origin)
			return;

		while (users_.size())
			(*users_.begin())->divert_to(new_origin);
	}

	inline user_iterator
	begin() const noexcept
	{
		return users_.begin();
	}

	inline user_iterator
	end() const noexcept
	{
		return users_.end();
	}

	inline const jive::type &
	type() const noexcept
	{
		return port_->type();
	}

	inline jive::region *
	region() const noexcept
	{
		return region_;
	}

	inline const jive::port &
	port() const noexcept
	{
		return *port_;
	}

	virtual jive::node *
	node() const noexcept = 0;

	virtual std::string
	debug_string() const;

	inline void
	replace(const jive::port & port)
	{
		if (port_->type() != port.type())
			throw type_error(port_->type().debug_string(), port.type().debug_string());

		port_ = port.copy();
	}

private:
	void
	remove_user(jive::input * user);

	void
	add_user(jive::input * user);

	size_t index_;
	jive::region * region_;
	std::unique_ptr<jive::port> port_;
	std::unordered_set<jive::input*> users_;
};

/* node_input class */

class node_input : public jive::input {
public:
	node_input(
		jive::output * origin,
		jive::node * node,
		const jive::port & port);

	virtual jive::node *
	node() const noexcept override;

private:
	jive::node * node_;
};

/* node_output class */

class node_output : public jive::output {
public:
	node_output(
		jive::node * node,
		const jive::port & port);

	jive::node *
	node() const noexcept override;

private:
	jive::node * node_;
};

/* node class */

class node {
public:
	virtual
	~node();

	node(std::unique_ptr<jive::operation> op, jive::region * region);

	inline const jive::operation &
	operation() const noexcept
	{
		return *operation_;
	}

	inline bool
	has_users() const noexcept
	{
		for (const auto & output : outputs_) {
			if (output->nusers() != 0)
				return true;
		}

		return false;
	}

	inline bool
	has_predecessors() const noexcept
	{
		for (const auto & input : inputs_) {
			if (input->origin()->node())
				return true;
		}

		return false;
	}

	inline bool
	has_successors() const noexcept
	{
		for (const auto & output : outputs_) {
			for (const auto & user : *output) {
				if (user->node())
					return true;
			}
		}

		return false;
	}

	inline size_t
	ninputs() const noexcept
	{
		return inputs_.size();
	}

	node_input *
	input(size_t index) const noexcept
	{
		JIVE_DEBUG_ASSERT(index < ninputs());
		return inputs_[index].get();
	}

	inline size_t
	noutputs() const noexcept
	{
		return outputs_.size();
	}

	node_output *
	output(size_t index) const noexcept
	{
		JIVE_DEBUG_ASSERT(index < noutputs());
		return outputs_[index].get();
	}

	inline void
	recompute_depth() noexcept;

protected:
	node_input *
	add_input(std::unique_ptr<node_input> input);

	void
	remove_input(size_t index);

	node_output *
	add_output(std::unique_ptr<node_output> output)
	{
		output->index_ = noutputs();
		outputs_.push_back(std::move(output));
		return this->output(noutputs()-1);
	}

	void
	remove_output(size_t index);

public:
	inline jive::graph *
	graph() const noexcept
	{
		return graph_;
	}

	inline jive::region *
	region() const noexcept
	{
		return region_;
	}

	virtual jive::node *
	copy(jive::region * region, const std::vector<jive::output*> & operands) const;

	/**
		\brief Copy a node with substitutions
		\param self Node to be copied
		\param target Target region to create node in
		\param substitution Operand substitutions
		\return Copied node

		Create a new node that is semantically equivalent to an
		existing node. The newly created node will use the same
		operands as the existing node unless there is a substitution
		registered for a particular operand.

		The given substitution map is updated so that all
		outputs of the original node will be substituted by
		corresponding outputs of the newly created node in
		subsequent \ref copy operations.
	*/
	virtual jive::node *
	copy(jive::region * region, jive::substitution_map & smap) const = 0;

	inline size_t
	depth() const noexcept
	{
		return depth_;
	}

private:
	jive::detail::intrusive_list_anchor<
		jive::node
	> region_node_list_anchor_;

	jive::detail::intrusive_list_anchor<
		jive::node
	> region_top_node_list_anchor_;

	jive::detail::intrusive_list_anchor<
		jive::node
	> region_bottom_node_list_anchor_;

public:
	typedef jive::detail::intrusive_list_accessor<
		jive::node,
		&jive::node::region_node_list_anchor_
	> region_node_list_accessor;

	typedef jive::detail::intrusive_list_accessor<
		jive::node,
		&jive::node::region_top_node_list_anchor_
	> region_top_node_list_accessor;

	typedef jive::detail::intrusive_list_accessor<
		jive::node,
		&jive::node::region_bottom_node_list_anchor_
	> region_bottom_node_list_accessor;

private:
	size_t depth_;
	jive::graph * graph_;
	jive::region * region_;
	std::unique_ptr<jive::operation> operation_;
	std::vector<std::unique_ptr<node_input>> inputs_;
	std::vector<std::unique_ptr<node_output>> outputs_;
};

static inline std::vector<jive::output*>
operands(const jive::node * node)
{
	std::vector<jive::output*> operands;
	for (size_t n = 0; n < node->ninputs(); n++)
		operands.push_back(node->input(n)->origin());
	return operands;
}

static inline std::vector<jive::output*>
outputs(const jive::node * node)
{
	std::vector<jive::output*> outputs;
	for (size_t n = 0; n < node->noutputs(); n++)
		outputs.push_back(node->output(n));
	return outputs;
}

static inline void
divert_users(
	jive::node * node,
	const std::vector<jive::output*> & outputs)
{
	JIVE_DEBUG_ASSERT(node->noutputs() == outputs.size());

	for (size_t n = 0; n < outputs.size(); n++)
		node->output(n)->divert_users(outputs[n]);
}

template <class T> static inline bool
is(const jive::node * node) noexcept
{
	if (!node)
		return false;

	return is<T>(node->operation());
}

jive::node *
producer(const jive::output * output) noexcept;

bool
normalize(jive::node * node);

}

#endif
<|endoftext|>


<commit_before>#ifndef KGR_INCLUDE_KANGARU_GENERIC_HPP
#define KGR_INCLUDE_KANGARU_GENERIC_HPP

#include "container.hpp"
#include "detail/injected.hpp"
#include "detail/function_traits.hpp"

namespace kgr {

template<typename CRTP, typename Type>
struct GenericService {
	friend struct Container;
	using Self = CRTP;

	GenericService() = default;

	GenericService(GenericService&& other) {
		emplace(std::move(other.getInstance()));
	}

	GenericService& operator=(GenericService&& other) {
		emplace(std::move(other.getInstance()));
		return *this;
	}

	GenericService(const GenericService& other) {
		emplace(other.getInstance());
	}

	GenericService& operator=(const GenericService& other) {
		emplace(other.getInstance());
		return *this;
	}

	template<typename... Args, detail::enable_if_t<detail::is_someway_constructible<Type, Args...>, int> = 0>
	GenericService(in_place_t, Args&&... args) {
		emplace(std::forward<Args>(args)...);
	}

	~GenericService() {
		getInstance().~Type();
	}

protected:
	template<typename F, typename... T>
	void autocall(Inject<T>... others) {
		CRTP::call(getInstance(), F::value, std::forward<Inject<T>>(others).forward()...);
	}

	template<typename F, template<typename> class Map>
	void autocall(Inject<ContainerService> cs) {
		autocall<Map, F>(detail::tuple_seq<detail::function_arguments_t<typename F::value_type>>{}, std::move(cs));
	}

	Type& getInstance() {
		return *reinterpret_cast<Type*>(&_instance);
	}

	const Type& getInstance() const {
		return *reinterpret_cast<const Type*>(&_instance);
	}

private:
	template<typename... Args, detail::enable_if_t<std::is_constructible<Type, Args...>::value, int> = 0>
	void emplace(Args&&... args) {
		new (&_instance) Type(std::forward<Args>(args)...);
	}

	template<typename... Args, detail::enable_if_t<!std::is_constructible<Type, Args...>::value && detail::is_brace_constructible<Type, Args...>::value, int> = 0>
	void emplace(Args&&... args) {
		new (&_instance) Type{std::forward<Args>(args)...};
	}

	template<template<typename> class Map, typename F, std::size_t... S>
	void autocall(detail::seq<S...>, Inject<ContainerService> cs) {
		cs.forward().invoke<Map>([this](detail::function_argument_t<S, typename F::value_type>... args){
			CRTP::call(getInstance(), F::value, std::forward<detail::function_argument_t<S, typename F::value_type>>(args)...);
		});
	}

	typename std::aligned_storage<sizeof(Type), alignof(Type)>::type _instance;
};

} // namespace kgr

#endif // KGR_INCLUDE_KANGARU_GENERIC_HPP
<commit_msg>better name<commit_after>#ifndef KGR_INCLUDE_KANGARU_GENERIC_HPP
#define KGR_INCLUDE_KANGARU_GENERIC_HPP

#include "container.hpp"
#include "detail/injected.hpp"
#include "detail/function_traits.hpp"

namespace kgr {

template<typename CRTP, typename Type>
struct GenericService {
	friend struct Container;
	using Self = CRTP;

	GenericService() = default;

	GenericService(GenericService&& other) {
		emplace(std::move(other.getInstance()));
	}

	GenericService& operator=(GenericService&& other) {
		emplace(std::move(other.getInstance()));
		return *this;
	}

	GenericService(const GenericService& other) {
		emplace(other.getInstance());
	}

	GenericService& operator=(const GenericService& other) {
		emplace(other.getInstance());
		return *this;
	}

	template<typename... Args, detail::enable_if_t<detail::is_someway_constructible<Type, Args...>::value, int> = 0>
	GenericService(in_place_t, Args&&... args) {
		emplace(std::forward<Args>(args)...);
	}

	~GenericService() {
		getInstance().~Type();
	}

protected:
	template<typename F, typename... T>
	void autocall(Inject<T>... others) {
		CRTP::call(getInstance(), F::value, std::forward<Inject<T>>(others).forward()...);
	}

	template<typename F, template<typename> class Map>
	void autocall(Inject<ContainerService> cs) {
		autocall<Map, F>(detail::tuple_seq<detail::function_arguments_t<typename F::value_type>>{}, std::move(cs));
	}

	Type& getInstance() {
		return *reinterpret_cast<Type*>(&_instance);
	}

	const Type& getInstance() const {
		return *reinterpret_cast<const Type*>(&_instance);
	}

private:
	template<typename... Args, detail::enable_if_t<std::is_constructible<Type, Args...>::value, int> = 0>
	void emplace(Args&&... args) {
		new (&_instance) Type(std::forward<Args>(args)...);
	}

	template<typename... Args, detail::enable_if_t<!std::is_constructible<Type, Args...>::value && detail::is_brace_constructible<Type, Args...>::value, int> = 0>
	void emplace(Args&&... args) {
		new (&_instance) Type{std::forward<Args>(args)...};
	}

	template<template<typename> class Map, typename F, std::size_t... S>
	void autocall(detail::seq<S...>, Inject<ContainerService> cs) {
		cs.forward().invoke<Map>([this](detail::function_argument_t<S, typename F::value_type>... args){
			CRTP::call(getInstance(), F::value, std::forward<detail::function_argument_t<S, typename F::value_type>>(args)...);
		});
	}

	typename std::aligned_storage<sizeof(Type), alignof(Type)>::type _instance;
};

} // namespace kgr

#endif // KGR_INCLUDE_KANGARU_GENERIC_HPP
<|endoftext|>