<commit_before>// Copyright (c) 2015 Chaobin Zhang. All rights reserved.
// Use of this source code is governed by the BSD license that can be
// found in the LICENSE file.

#include "master/master_main_runner.h"

#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/hash.h"
#include "base/sys_info.h"
#include "base/threading/thread_restrictions.h"
#include "common/util.h"
#include "curl/curl.h"
#include "master/master_rpc.h"
#include "ninja/dn_builder.h"
#include "ninja/ninja_main.h"
#include "thread/ninja_thread.h"

namespace {

const char kHttp[] = "http://";

size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
  return fwrite(ptr, size, nmemb, stream);
}

void FetchTargetsOnBlockingPool(const std::string& host,
                                const std::vector<std::string>& targets) {
  CURL* curl = curl_easy_init();
  for (size_t i = 0; i < targets.size(); ++i) {
    base::FilePath filename = base::FilePath::FromUTF8Unsafe(targets[i]);
    CHECK(base::CreateDirectory(filename.DirName()));
    std::string url = kHttp + host + "/" + targets[i];
    base::ScopedFILE file(base::OpenFile(filename, "wb"));
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, file.get());
    CHECK(curl_easy_perform(curl) == CURLE_OK);
  }
  curl_easy_cleanup(curl);
}

}  // namespace

namespace master {

MasterMainRunner::MasterMainRunner(const std::string& bind_ip, uint16 port)
    : bind_ip_(bind_ip),
      port_(port),
      number_of_slave_processors_(0) {
  // |curl_global_init| is not thread-safe, following advice in docs of
  // |curl_easy_init|, we call it manually.
  curl_global_init(CURL_GLOBAL_ALL);
}

MasterMainRunner::~MasterMainRunner() {
  curl_global_cleanup();
}

bool MasterMainRunner::PostCreateThreads() {
  master_rpc_.reset(new MasterRPC(bind_ip_, port_, this));
  return true;
}

void MasterMainRunner::StartBuild() {
  std::string error;
  config_.parallelism = common::GuessParallelism();
  ninja_main()->RunBuild(ninja_main()->state().DefaultNodes(&error), this);
}

bool MasterMainRunner::LocalCanRunMore() {
  size_t subproc_number =
      subprocs_.running_.size() + subprocs_.finished_.size();
  return static_cast<int>(subproc_number) < config_.parallelism;
}

bool MasterMainRunner::RemoteCanRunMore() {
  return static_cast<int>(outstanding_edges_.size()) <=
      number_of_slave_processors_;
}

bool MasterMainRunner::StartCommand(Edge* edge, bool run_in_local) {
  if (run_in_local)
    return StartCommandLocally(edge);
  else
    return StartCommandRemotely(edge);
}

bool MasterMainRunner::StartCommandLocally(Edge* edge) {
  base::ThreadRestrictions::AssertIOAllowed();

  // Create directories necessary for outputs.
  for (vector<Node*>::iterator o = edge->outputs_.begin();
       o != edge->outputs_.end(); ++o) {
    if (!ninja_main()->disk_interface()->MakeDirs((*o)->path()))
      return false;
  }

  // Create response file, if needed
  std::string rspfile = edge->GetUnescapedRspfile();
  if (!rspfile.empty()) {
    std::string content = edge->GetBinding("rspfile_content");
    if (!ninja_main()->disk_interface()->WriteFile(rspfile, content))
      return false;
  }

  std::string command = edge->EvaluateCommand();
  Subprocess* subproc = subprocs_.Add(command, edge->use_console());
  if (!subproc)
    return false;
  subproc_to_edge_.insert(make_pair(subproc, edge));
  return true;
}

bool MasterMainRunner::StartCommandRemotely(Edge* edge) {
  int connection_id = FindMostAvailableSlave();
  if (connection_id == INT_MIN)
    return false;

  MasterRPC::Directories dirs;
  for (vector<Node*>::iterator o = edge->outputs_.begin();
       o != edge->outputs_.end();
       ++o) {
    dirs.push_back((*o)->path());
  }

  std::string command = edge->EvaluateCommand();
  uint32 edge_id = base::Hash(command);
  outstanding_edges_[edge_id] = edge;
  NinjaThread::PostTask(
      NinjaThread::RPC,
      FROM_HERE,
      base::Bind(&MasterRPC::StartCommandRemotely,
                 base::Unretained(master_rpc_.get()),
                 connection_id,
                 dirs,
                 edge->GetUnescapedRspfile(),
                 edge->GetBinding("rspfile_content"),
                 command,
                 edge_id));
  return true;
}

bool MasterMainRunner::WaitForCommand(CommandRunner::Result* result) {
  Subprocess* subproc;
  while ((subproc = subprocs_.NextFinished()) == NULL) {
    bool interrupted = subprocs_.DoWork();
    if (interrupted)
      return false;
  }

  result->status = subproc->Finish();
  result->output = subproc->GetOutput();

  SubprocessToEdgeMap::iterator e = subproc_to_edge_.find(subproc);
  result->edge = e->second;
  subproc_to_edge_.erase(e);

  delete subproc;
  return true;
}

std::vector<Edge*> MasterMainRunner::GetActiveEdges() {
  std::vector<Edge*> edges;
  for (SubprocessToEdgeMap::iterator e = subproc_to_edge_.begin();
       e != subproc_to_edge_.end(); ++e)
    edges.push_back(e->second);
  return edges;
}

void MasterMainRunner::Abort() {
  subprocs_.Clear();
}

bool MasterMainRunner::HasPendingLocalCommands() {
  return !subproc_to_edge_.empty();
}

void MasterMainRunner::OnFetchTargetsDone(CommandRunner::Result result) {
  DCHECK(NinjaThread::CurrentlyOn(NinjaThread::MAIN));
  std::string error;
  if (!ninja_main()->builder()->HasRemoteCommandRunLocally(result.edge))
    ninja_main()->builder()->FinishCommand(&result, &error);
}

void MasterMainRunner::OnRemoteCommandDone(int connection_id,
                                           uint32 edge_id,
                                           ExitStatus status,
                                           const std::string& output) {
  OutstandingEdgeMap::iterator it = outstanding_edges_.find(edge_id);
  DCHECK(it != outstanding_edges_.end());
  CommandRunner::Result result;
  result.edge = it->second;
  result.status = status;
  result.output = output;  // The output stream of the command.
  outstanding_edges_.erase(it);
  std::string error;
  if (status != ExitSuccess) {
    ninja_main()->builder()->FinishCommand(&result, &error);
    return;
  }

  std::vector<std::string> targets;
  for (size_t i = 0; i < result.edge->outputs_.size(); ++i)
    targets.push_back(result.edge->outputs_[i]->path());

  DCHECK(slave_info_id_map_.find(connection_id) != slave_info_id_map_.end());
  // TODO(zhchbin): Remove hard code 8080.
  std::string host = slave_info_id_map_[connection_id].ip + ":" + "8080";

  NinjaThread::PostBlockingPoolTaskAndReply(
      FROM_HERE,
      base::Bind(FetchTargetsOnBlockingPool, host, targets),
      base::Bind(&MasterMainRunner::OnFetchTargetsDone, this, result));
}

void MasterMainRunner::OnSlaveSystemInfoAvailable(int connection_id,
                                                  const SlaveInfo& info) {
  if (slave_info_id_map_.find(connection_id) != slave_info_id_map_.end())
    return;
  if (info.operating_system_name != base::SysInfo::OperatingSystemName() ||
      info.operating_system_architecture !=
          base::SysInfo::OperatingSystemArchitecture()) {
    static const string kRejectReason =
        "Different system name or architecture, system info of master: \"" +
        base::SysInfo::OperatingSystemName() + ", " +
        base::SysInfo::OperatingSystemArchitecture() + "\".";

    NinjaThread::PostTask(
        NinjaThread::RPC,
        FROM_HERE,
        base::Bind(&MasterRPC::QuitSlave,
                   base::Unretained(master_rpc_.get()),
                   connection_id,
                   kRejectReason));
    return;
  }

  slave_info_id_map_[connection_id] = info;
  number_of_slave_processors_ += info.number_of_processors;
}

void MasterMainRunner::OnSlaveStatusUpdate(
    int connection_id,
    double load_average,
    int amount_of_running_commands,
    int64 amount_of_available_physical_memory) {
  // Don't update the status until |OnSlaveSystemInfoAvailable| is called.
  SlaveInfoIdMap::iterator it = slave_info_id_map_.find(connection_id);
  if (it == slave_info_id_map_.end())
    return;

  it->second.load_average = load_average;
  it->second.amount_of_running_commands = amount_of_running_commands;
  it->second.amount_of_available_physical_memory =
      amount_of_available_physical_memory;
}

void MasterMainRunner::OnSlaveClose(int connection_id) {
  DCHECK(slave_info_id_map_.find(connection_id) != slave_info_id_map_.end());
  slave_info_id_map_.erase(connection_id);
}

int MasterMainRunner::FindMostAvailableSlave() {
  int connection_id = INT_MIN;
  int max_number_of_available_processors = INT_MIN;
  for (SlaveInfoIdMap::iterator it = slave_info_id_map_.begin();
       it != slave_info_id_map_.end();
       ++it) {
    int tmp =
        it->second.number_of_processors - it->second.amount_of_running_commands;
    if (tmp > max_number_of_available_processors) {
      tmp = max_number_of_available_processors;
      connection_id = it->first;
    }
  }

  return connection_id;
}

}  // namespace master
<commit_msg>:smile:<commit_after>// Copyright (c) 2015 Chaobin Zhang. All rights reserved.
// Use of this source code is governed by the BSD license that can be
// found in the LICENSE file.

#include "master/master_main_runner.h"

#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/hash.h"
#include "base/sys_info.h"
#include "base/threading/thread_restrictions.h"
#include "common/util.h"
#include "curl/curl.h"
#include "master/master_rpc.h"
#include "ninja/dn_builder.h"
#include "ninja/ninja_main.h"
#include "thread/ninja_thread.h"

namespace {

const char kHttp[] = "http://";

size_t write_data(void* ptr, size_t size, size_t count, FILE* stream) {
  return fwrite(ptr, size, count, stream);
}

void FetchTargetsOnBlockingPool(const std::string& host,
                                const std::vector<std::string>& targets) {
  CURL* curl = curl_easy_init();
  for (size_t i = 0; i < targets.size(); ++i) {
    base::FilePath filename = base::FilePath::FromUTF8Unsafe(targets[i]);
    CHECK(base::CreateDirectory(filename.DirName()));
    std::string url = kHttp + host + "/" + targets[i];
    base::ScopedFILE file(base::OpenFile(filename, "wb"));
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, file.get());
    CHECK(curl_easy_perform(curl) == CURLE_OK);
  }
  curl_easy_cleanup(curl);
}

}  // namespace

namespace master {

MasterMainRunner::MasterMainRunner(const std::string& bind_ip, uint16 port)
    : bind_ip_(bind_ip),
      port_(port),
      number_of_slave_processors_(0) {
  // |curl_global_init| is not thread-safe, following advice in docs of
  // |curl_easy_init|, we call it manually.
  curl_global_init(CURL_GLOBAL_ALL);
}

MasterMainRunner::~MasterMainRunner() {
  curl_global_cleanup();
}

bool MasterMainRunner::PostCreateThreads() {
  master_rpc_.reset(new MasterRPC(bind_ip_, port_, this));
  return true;
}

void MasterMainRunner::StartBuild() {
  std::string error;
  config_.parallelism = common::GuessParallelism();
  ninja_main()->RunBuild(ninja_main()->state().DefaultNodes(&error), this);
}

bool MasterMainRunner::LocalCanRunMore() {
  size_t subproc_number =
      subprocs_.running_.size() + subprocs_.finished_.size();
  return static_cast<int>(subproc_number) < config_.parallelism;
}

bool MasterMainRunner::RemoteCanRunMore() {
  return static_cast<int>(outstanding_edges_.size()) <=
      number_of_slave_processors_;
}

bool MasterMainRunner::StartCommand(Edge* edge, bool run_in_local) {
  if (run_in_local)
    return StartCommandLocally(edge);
  else
    return StartCommandRemotely(edge);
}

bool MasterMainRunner::StartCommandLocally(Edge* edge) {
  base::ThreadRestrictions::AssertIOAllowed();

  // Create directories necessary for outputs.
  for (vector<Node*>::iterator o = edge->outputs_.begin();
       o != edge->outputs_.end(); ++o) {
    if (!ninja_main()->disk_interface()->MakeDirs((*o)->path()))
      return false;
  }

  // Create response file, if needed
  std::string rspfile = edge->GetUnescapedRspfile();
  if (!rspfile.empty()) {
    std::string content = edge->GetBinding("rspfile_content");
    if (!ninja_main()->disk_interface()->WriteFile(rspfile, content))
      return false;
  }

  std::string command = edge->EvaluateCommand();
  Subprocess* subproc = subprocs_.Add(command, edge->use_console());
  if (!subproc)
    return false;
  subproc_to_edge_.insert(make_pair(subproc, edge));
  return true;
}

bool MasterMainRunner::StartCommandRemotely(Edge* edge) {
  int connection_id = FindMostAvailableSlave();
  if (connection_id == INT_MIN)
    return false;

  MasterRPC::Directories dirs;
  for (vector<Node*>::iterator o = edge->outputs_.begin();
       o != edge->outputs_.end();
       ++o) {
    dirs.push_back((*o)->path());
  }

  std::string command = edge->EvaluateCommand();
  uint32 edge_id = base::Hash(command);
  outstanding_edges_[edge_id] = edge;
  NinjaThread::PostTask(
      NinjaThread::RPC,
      FROM_HERE,
      base::Bind(&MasterRPC::StartCommandRemotely,
                 base::Unretained(master_rpc_.get()),
                 connection_id,
                 dirs,
                 edge->GetUnescapedRspfile(),
                 edge->GetBinding("rspfile_content"),
                 command,
                 edge_id));
  return true;
}

bool MasterMainRunner::WaitForCommand(CommandRunner::Result* result) {
  Subprocess* subproc;
  while ((subproc = subprocs_.NextFinished()) == NULL) {
    bool interrupted = subprocs_.DoWork();
    if (interrupted)
      return false;
  }

  result->status = subproc->Finish();
  result->output = subproc->GetOutput();

  SubprocessToEdgeMap::iterator e = subproc_to_edge_.find(subproc);
  result->edge = e->second;
  subproc_to_edge_.erase(e);

  delete subproc;
  return true;
}

std::vector<Edge*> MasterMainRunner::GetActiveEdges() {
  std::vector<Edge*> edges;
  for (SubprocessToEdgeMap::iterator e = subproc_to_edge_.begin();
       e != subproc_to_edge_.end(); ++e)
    edges.push_back(e->second);
  return edges;
}

void MasterMainRunner::Abort() {
  subprocs_.Clear();
}

bool MasterMainRunner::HasPendingLocalCommands() {
  return !subproc_to_edge_.empty();
}

void MasterMainRunner::OnFetchTargetsDone(CommandRunner::Result result) {
  DCHECK(NinjaThread::CurrentlyOn(NinjaThread::MAIN));
  std::string error;
  if (!ninja_main()->builder()->HasRemoteCommandRunLocally(result.edge))
    ninja_main()->builder()->FinishCommand(&result, &error);
}

void MasterMainRunner::OnRemoteCommandDone(int connection_id,
                                           uint32 edge_id,
                                           ExitStatus status,
                                           const std::string& output) {
  OutstandingEdgeMap::iterator it = outstanding_edges_.find(edge_id);
  DCHECK(it != outstanding_edges_.end());
  CommandRunner::Result result;
  result.edge = it->second;
  result.status = status;
  result.output = output;  // The output stream of the command.
  outstanding_edges_.erase(it);
  std::string error;
  if (status != ExitSuccess) {
    ninja_main()->builder()->FinishCommand(&result, &error);
    return;
  }

  std::vector<std::string> targets;
  for (size_t i = 0; i < result.edge->outputs_.size(); ++i)
    targets.push_back(result.edge->outputs_[i]->path());

  DCHECK(slave_info_id_map_.find(connection_id) != slave_info_id_map_.end());
  // TODO(zhchbin): Remove hard code 8080.
  std::string host = slave_info_id_map_[connection_id].ip + ":" + "8080";

  NinjaThread::PostBlockingPoolTaskAndReply(
      FROM_HERE,
      base::Bind(FetchTargetsOnBlockingPool, host, targets),
      base::Bind(&MasterMainRunner::OnFetchTargetsDone, this, result));
}

void MasterMainRunner::OnSlaveSystemInfoAvailable(int connection_id,
                                                  const SlaveInfo& info) {
  if (slave_info_id_map_.find(connection_id) != slave_info_id_map_.end())
    return;
  if (info.operating_system_name != base::SysInfo::OperatingSystemName() ||
      info.operating_system_architecture !=
          base::SysInfo::OperatingSystemArchitecture()) {
    static const string kRejectReason =
        "Different system name or architecture, system info of master: \"" +
        base::SysInfo::OperatingSystemName() + ", " +
        base::SysInfo::OperatingSystemArchitecture() + "\".";

    NinjaThread::PostTask(
        NinjaThread::RPC,
        FROM_HERE,
        base::Bind(&MasterRPC::QuitSlave,
                   base::Unretained(master_rpc_.get()),
                   connection_id,
                   kRejectReason));
    return;
  }

  slave_info_id_map_[connection_id] = info;
  number_of_slave_processors_ += info.number_of_processors;
}

void MasterMainRunner::OnSlaveStatusUpdate(
    int connection_id,
    double load_average,
    int amount_of_running_commands,
    int64 amount_of_available_physical_memory) {
  // Don't update the status until |OnSlaveSystemInfoAvailable| is called.
  SlaveInfoIdMap::iterator it = slave_info_id_map_.find(connection_id);
  if (it == slave_info_id_map_.end())
    return;

  it->second.load_average = load_average;
  it->second.amount_of_running_commands = amount_of_running_commands;
  it->second.amount_of_available_physical_memory =
      amount_of_available_physical_memory;
}

void MasterMainRunner::OnSlaveClose(int connection_id) {
  DCHECK(slave_info_id_map_.find(connection_id) != slave_info_id_map_.end());
  slave_info_id_map_.erase(connection_id);
}

int MasterMainRunner::FindMostAvailableSlave() {
  int connection_id = INT_MIN;
  int max_number_of_available_processors = INT_MIN;
  for (SlaveInfoIdMap::iterator it = slave_info_id_map_.begin();
       it != slave_info_id_map_.end();
       ++it) {
    int tmp =
        it->second.number_of_processors - it->second.amount_of_running_commands;
    if (tmp > max_number_of_available_processors) {
      tmp = max_number_of_available_processors;
      connection_id = it->first;
    }
  }

  return connection_id;
}

}  // namespace master
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2022 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
#include <algorithm> // for std::copy, std::sort

// Local includes
#include "libmesh/mesh_smoother_laplace.h"
#include "libmesh/mesh_tools.h"
#include "libmesh/elem.h"
#include "libmesh/unstructured_mesh.h"
#include "libmesh/parallel.h"
#include "libmesh/parallel_ghost_sync.h" // sync_dofobject_data_by_id()
#include "libmesh/parallel_algebra.h" // StandardType<Point>
#include "libmesh/int_range.h"
#include "libmesh/elem_side_builder.h"

namespace libMesh
{
// LaplaceMeshSmoother member functions
LaplaceMeshSmoother::LaplaceMeshSmoother(UnstructuredMesh & mesh)
  : MeshSmoother(mesh),
    _initialized(false)
{
}

void LaplaceMeshSmoother::smooth(unsigned int n_iterations)
{
  if (!_initialized)
    this->init();

  // Don't smooth the nodes on the boundary...
  // this would change the mesh geometry which
  // is probably not something we want!
  auto on_boundary = MeshTools::find_boundary_nodes(_mesh);

  // Also: don't smooth block bondary nodes
  auto on_block_boundary = MeshTools::find_block_boundary_nodes(_mesh);

  // Merge them
  on_boundary.insert(on_block_boundary.begin(), on_block_boundary.end());

  // We can only update the nodes after all new positions were
  // determined. We store the new positions here
  std::vector<Point> new_positions;

  for (unsigned int n=0; n<n_iterations; n++)
    {
      new_positions.resize(_mesh.max_node_id());

      for (auto & node : _mesh.local_node_ptr_range())
        {
          libmesh_error_msg_if(node == nullptr,
                               "[" << _mesh.processor_id() << "]: Node iterator returned nullptr.");

          // leave the boundary intact
          // Only relocate the nodes which are vertices of an element
          // All other entries of _graph (the secondary nodes) are empty
          if (!on_boundary.count(node->id()) && (_graph[node->id()].size() > 0))
            {
              Point avg_position(0.,0.,0.);

              for (const auto & connected_id : _graph[node->id()])
                {
                  // Will these nodal positions always be available
                  // or will they refer to remote nodes?  This will
                  // fail an assertion in the latter case, which
                  // shouldn't occur if DistributedMesh is working
                  // correctly.
                  const Point & connected_node = _mesh.point(connected_id);

                  avg_position.add( connected_node );
                } // end for (j)

              // Compute the average, store in the new_positions vector
              new_positions[node->id()] = avg_position / static_cast<Real>(_graph[node->id()].size());
            } // end if
        } // end for

      // now update the node positions (local node positions only)
      for (auto & node : _mesh.local_node_ptr_range())
        if (!on_boundary.count(node->id()) && (_graph[node->id()].size() > 0))
          {
            // Should call Point::op=
            // libMesh::out << "Setting node id " << node->id() << " to position " << new_positions[node->id()];
            _mesh.node_ref(node->id()) = new_positions[node->id()];
          }

      // Now the nodes which are ghosts on this processor may have been moved on
      // the processors which own them.  So we need to synchronize with our neighbors
      // and get the most up-to-date positions for the ghosts.
      SyncNodalPositions sync_object(_mesh);
      Parallel::sync_dofobject_data_by_id
        (_mesh.comm(), _mesh.nodes_begin(), _mesh.nodes_end(), sync_object);

    } // end for n_iterations

  // finally adjust the second order nodes (those located between vertices)
  // these nodes will be located between their adjacent nodes
  // do this element-wise
  for (auto & elem : _mesh.active_element_ptr_range())
    {
      // get the second order nodes (son)
      // their element indices start at n_vertices and go to n_nodes
      const unsigned int son_begin = elem->n_vertices();
      const unsigned int son_end   = elem->n_nodes();

      // loop over all second order nodes (son)
      for (unsigned int son=son_begin; son<son_end; son++)
        {
          // Don't smooth second-order nodes which are on the boundary
          if (!on_boundary.count(elem->node_id(son)))
            {
              const unsigned int n_adjacent_vertices =
                elem->n_second_order_adjacent_vertices(son);

              // calculate the new position which is the average of the
              // position of the adjacent vertices
              Point avg_position(0,0,0);
              for (unsigned int v=0; v<n_adjacent_vertices; v++)
                avg_position +=
                  _mesh.point( elem->node_id( elem->second_order_adjacent_vertex(son,v) ) );

              _mesh.node_ref(elem->node_id(son)) = avg_position / n_adjacent_vertices;
            }
        }
    }
}

void LaplaceMeshSmoother::init()
{
  // For avoiding extraneous element side construction
  ElemSideBuilder side_builder;

  switch (_mesh.mesh_dimension())
    {

      // TODO:[BSK] Fix this to work for refined meshes...  I think
      // the implementation was done quickly for Damien, who did not have
      // refined grids.  Fix it here and in the original Mesh member.

    case 2: // Stolen directly from build_L_graph in mesh_base.C
      {
        // Initialize space in the graph.  It is indexed by node id.
        // Each node may be connected to an arbitrary number of other
        // nodes via edges.
        _graph.resize(_mesh.max_node_id());

        auto elem_to_graph =
          [this, &side_builder](const Elem & elem) {
          for (auto s : elem.side_index_range())
            {
              // Only operate on sides which are on the
              // boundary or for which the current element's
              // id is greater than its neighbor's.
              // Sides get only built once.
              if ((elem.neighbor_ptr(s) == nullptr) ||
                  (elem.id() > elem.neighbor_ptr(s)->id()))
                {
                  const Elem & side = side_builder(elem, s);
                  _graph[side.node_id(0)].push_back(side.node_id(1));
                  _graph[side.node_id(1)].push_back(side.node_id(0));
                }
            }
        };

        for (auto & elem : _mesh.active_local_element_ptr_range())
          elem_to_graph(*elem);

        if (!_mesh.processor_id())
          for (auto & elem : _mesh.active_unpartitioned_element_ptr_range())
            elem_to_graph(*elem);

        _initialized = true;
        break;
      } // case 2

    case 3: // Stolen blatantly from build_L_graph in mesh_base.C
      {
        // Extra builder for the face elements
        ElemSideBuilder face_builder;

        // Initialize space in the graph.
        _graph.resize(_mesh.max_node_id());

        auto elem_to_graph =
          [this, &side_builder, &face_builder](const Elem & elem) {
          for (auto f : elem.side_index_range()) // Loop over faces
            if ((elem.neighbor_ptr(f) == nullptr) ||
                (elem.id() > elem.neighbor_ptr(f)->id()))
              {
                const Elem & face = face_builder(elem, f);

                for (auto s : face.side_index_range()) // Loop over face's edges
                  {
                    const Elem & side = side_builder(face, s);

                    // At this point, we just insert the node numbers
                    // again.  At the end we'll call sort and unique
                    // to make sure there are no duplicates
                    _graph[side.node_id(0)].push_back(side.node_id(1));
                    _graph[side.node_id(1)].push_back(side.node_id(0));
                  }
              }
        };

        for (auto & elem : _mesh.active_local_element_ptr_range())
          elem_to_graph(*elem);

        if (!_mesh.processor_id())
          for (auto & elem : _mesh.active_unpartitioned_element_ptr_range())
            elem_to_graph(*elem);

        _initialized = true;
        break;
      } // case 3

    default:
      libmesh_error_msg("At this time it is not possible to smooth a dimension " << _mesh.mesh_dimension() << "mesh.  Aborting...");
    }

  // Done building graph from local and/or unpartitioned elements.
  // Let's now allgather the graph so that it is available on all
  // processors for the actual smoothing operation.
  this->allgather_graph();

  // In 3D, it's possible for > 2 processor partitions to meet
  // at a single edge, while in 2D only 2 processor partitions
  // share an edge.  Therefore the allgather'd graph in 3D may
  // now have duplicate entries and we need to remove them so
  // they don't foul up the averaging algorithm employed by the
  // Laplace smoother.
  for (auto & id_vec : _graph)
    {
      // The std::unique algorithm removes duplicate *consecutive* elements from a range,
      // so it only makes sense to call it on a sorted range...
      std::sort(id_vec.begin(), id_vec.end());
      id_vec.erase(std::unique(id_vec.begin(), id_vec.end()), id_vec.end());
    }

} // init()

void LaplaceMeshSmoother::print_graph(std::ostream & out_stream) const
{
  for (auto i : index_range(_graph))
    {
      out_stream << i << ": ";
      std::copy(_graph[i].begin(),
                _graph[i].end(),
                std::ostream_iterator<unsigned>(out_stream, " "));
      out_stream << std::endl;
    }
}

void LaplaceMeshSmoother::allgather_graph()
{
  // The graph data structure is not well-suited for parallel communication,
  // so copy the graph into a single vector defined by:
  // NA A_0 A_1 ... A_{NA} | NB B_0 B_1 ... B_{NB} | NC C_0 C_1 ... C_{NC}
  // where:
  // * NA is the number of graph connections for node A
  // * A_0, A_1, etc. are the IDs connected to node A
  std::vector<dof_id_type> flat_graph;

  // Reserve at least enough space for each node to have zero entries
  flat_graph.reserve(_graph.size());

  for (const auto & id_vec : _graph)
    {
      // First push back the number of entries for this node
      flat_graph.push_back (cast_int<dof_id_type>(id_vec.size()));

      // Then push back all the IDs
      for (const auto & dof : id_vec)
        flat_graph.push_back(dof);
    }

  // // A copy of the flat graph (for printing only, delete me later)
  // std::vector<unsigned> copy_of_flat_graph(flat_graph);

  // Use the allgather routine to combine all the flat graphs on all processors
  _mesh.comm().allgather(flat_graph);

  // Now reconstruct _graph from the allgathered flat_graph.

  // // (Delete me later, the copy is just for printing purposes.)
  // std::vector<std::vector<unsigned >> copy_of_graph(_graph);

  // Make sure the old graph is cleared out
  _graph.clear();
  _graph.resize(_mesh.max_node_id());

  // Our current position in the allgather'd flat_graph
  std::size_t cursor=0;

  // There are max_node_id * n_processors entries to read in total
  for (processor_id_type p=0; p<_mesh.n_processors(); ++p)
    for (dof_id_type node_ctr=0; node_ctr<_mesh.max_node_id(); ++node_ctr)
      {
        // Read the number of entries for this node, move cursor
        std::size_t n_entries = flat_graph[cursor++];

        // Reserve space for that many more entries, then push back
        _graph[node_ctr].reserve(_graph[node_ctr].size() + n_entries);

        // Read all graph connections for this node, move the cursor each time
        // Note: there might be zero entries but that's fine
        for (std::size_t i=0; i<n_entries; ++i)
          _graph[node_ctr].push_back(flat_graph[cursor++]);
      }

  // // Print local graph to uniquely named file (debugging)
  // {
  //   // Generate unique filename for this processor
  //   std::ostringstream oss;
  //   oss << "graph_filename_" << _mesh.processor_id() << ".txt";
  //   std::ofstream graph_stream(oss.str().c_str());
  //
  //   // Print the local non-flat graph
  //   std::swap(_graph, copy_of_graph);
  //   print_graph(graph_stream);
  //
  //   // Print the (local) flat graph for verification
  //   for (const auto & dof : copy_of_flat_graph)
  //     graph_stream << dof << " ";
  //   graph_stream << "\n";
  //
  //   // Print the allgather'd grap for verification
  //   for (const auto & dof : flat_graph)
  //     graph_stream << dof << " ";
  //   graph_stream << "\n";
  //
  //   // Print the global non-flat graph
  //   std::swap(_graph, copy_of_graph);
  //   print_graph(graph_stream);
  // }
} // allgather_graph()

} // namespace libMesh
<commit_msg>Smooth non-partitioned nodes too.<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2022 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
#include <algorithm> // for std::copy, std::sort

// Local includes
#include "libmesh/mesh_smoother_laplace.h"
#include "libmesh/mesh_tools.h"
#include "libmesh/elem.h"
#include "libmesh/unstructured_mesh.h"
#include "libmesh/parallel.h"
#include "libmesh/parallel_ghost_sync.h" // sync_dofobject_data_by_id()
#include "libmesh/parallel_algebra.h" // StandardType<Point>
#include "libmesh/int_range.h"
#include "libmesh/elem_side_builder.h"

namespace libMesh
{
// LaplaceMeshSmoother member functions
LaplaceMeshSmoother::LaplaceMeshSmoother(UnstructuredMesh & mesh)
  : MeshSmoother(mesh),
    _initialized(false)
{
}

void LaplaceMeshSmoother::smooth(unsigned int n_iterations)
{
  if (!_initialized)
    this->init();

  // Don't smooth the nodes on the boundary...
  // this would change the mesh geometry which
  // is probably not something we want!
  auto on_boundary = MeshTools::find_boundary_nodes(_mesh);

  // Also: don't smooth block bondary nodes
  auto on_block_boundary = MeshTools::find_block_boundary_nodes(_mesh);

  // Merge them
  on_boundary.insert(on_block_boundary.begin(), on_block_boundary.end());

  // We can only update the nodes after all new positions were
  // determined. We store the new positions here
  std::vector<Point> new_positions;

  for (unsigned int n=0; n<n_iterations; n++)
    {
      new_positions.resize(_mesh.max_node_id());

      auto calculate_new_position = [this, &on_boundary, &new_positions](const Node * node) {
        // leave the boundary intact
        // Only relocate the nodes which are vertices of an element
        // All other entries of _graph (the secondary nodes) are empty
        if (!on_boundary.count(node->id()) && (_graph[node->id()].size() > 0))
          {
            Point avg_position(0.,0.,0.);

            for (const auto & connected_id : _graph[node->id()])
              {
                // Will these nodal positions always be available
                // or will they refer to remote nodes?  This will
                // fail an assertion in the latter case, which
                // shouldn't occur if DistributedMesh is working
                // correctly.
                const Point & connected_node = _mesh.point(connected_id);

                avg_position.add( connected_node );
              } // end for (j)

            // Compute the average, store in the new_positions vector
            new_positions[node->id()] = avg_position / static_cast<Real>(_graph[node->id()].size());
          } // end if
      };

      // calculate new node positions (local and unpartitioned nodes only)
      for (auto & node : _mesh.local_node_ptr_range())
        calculate_new_position(node);

      for (auto & node : as_range(_mesh.pid_nodes_begin(DofObject::invalid_processor_id),
                                  _mesh.pid_nodes_end(DofObject::invalid_processor_id)))
        calculate_new_position(node);

      // now update the node positions (local and unpartitioned nodes only)
      for (auto & node : _mesh.local_node_ptr_range())
        if (!on_boundary.count(node->id()) && (_graph[node->id()].size() > 0))
          *node = new_positions[node->id()];

      for (auto & node : as_range(_mesh.pid_nodes_begin(DofObject::invalid_processor_id),
                                  _mesh.pid_nodes_end(DofObject::invalid_processor_id)))
        if (!on_boundary.count(node->id()) && (_graph[node->id()].size() > 0))
          *node = new_positions[node->id()];

      // Now the nodes which are ghosts on this processor may have been moved on
      // the processors which own them.  So we need to synchronize with our neighbors
      // and get the most up-to-date positions for the ghosts.
      SyncNodalPositions sync_object(_mesh);
      Parallel::sync_dofobject_data_by_id
        (_mesh.comm(), _mesh.nodes_begin(), _mesh.nodes_end(), sync_object);

    } // end for n_iterations

  // finally adjust the second order nodes (those located between vertices)
  // these nodes will be located between their adjacent nodes
  // do this element-wise
  for (auto & elem : _mesh.active_element_ptr_range())
    {
      // get the second order nodes (son)
      // their element indices start at n_vertices and go to n_nodes
      const unsigned int son_begin = elem->n_vertices();
      const unsigned int son_end   = elem->n_nodes();

      // loop over all second order nodes (son)
      for (unsigned int son=son_begin; son<son_end; son++)
        {
          // Don't smooth second-order nodes which are on the boundary
          if (!on_boundary.count(elem->node_id(son)))
            {
              const unsigned int n_adjacent_vertices =
                elem->n_second_order_adjacent_vertices(son);

              // calculate the new position which is the average of the
              // position of the adjacent vertices
              Point avg_position(0,0,0);
              for (unsigned int v=0; v<n_adjacent_vertices; v++)
                avg_position +=
                  _mesh.point( elem->node_id( elem->second_order_adjacent_vertex(son,v) ) );

              _mesh.node_ref(elem->node_id(son)) = avg_position / n_adjacent_vertices;
            }
        }
    }
}

void LaplaceMeshSmoother::init()
{
  // For avoiding extraneous element side construction
  ElemSideBuilder side_builder;

  switch (_mesh.mesh_dimension())
    {

      // TODO:[BSK] Fix this to work for refined meshes...  I think
      // the implementation was done quickly for Damien, who did not have
      // refined grids.  Fix it here and in the original Mesh member.

    case 2: // Stolen directly from build_L_graph in mesh_base.C
      {
        // Initialize space in the graph.  It is indexed by node id.
        // Each node may be connected to an arbitrary number of other
        // nodes via edges.
        _graph.resize(_mesh.max_node_id());

        auto elem_to_graph =
          [this, &side_builder](const Elem & elem) {
          for (auto s : elem.side_index_range())
            {
              // Only operate on sides which are on the
              // boundary or for which the current element's
              // id is greater than its neighbor's.
              // Sides get only built once.
              if ((elem.neighbor_ptr(s) == nullptr) ||
                  (elem.id() > elem.neighbor_ptr(s)->id()))
                {
                  const Elem & side = side_builder(elem, s);
                  _graph[side.node_id(0)].push_back(side.node_id(1));
                  _graph[side.node_id(1)].push_back(side.node_id(0));
                }
            }
        };

        for (auto & elem : _mesh.active_local_element_ptr_range())
          elem_to_graph(*elem);

        if (!_mesh.processor_id())
          for (auto & elem : _mesh.active_unpartitioned_element_ptr_range())
            elem_to_graph(*elem);

        _initialized = true;
        break;
      } // case 2

    case 3: // Stolen blatantly from build_L_graph in mesh_base.C
      {
        // Extra builder for the face elements
        ElemSideBuilder face_builder;

        // Initialize space in the graph.
        _graph.resize(_mesh.max_node_id());

        auto elem_to_graph =
          [this, &side_builder, &face_builder](const Elem & elem) {
          for (auto f : elem.side_index_range()) // Loop over faces
            if ((elem.neighbor_ptr(f) == nullptr) ||
                (elem.id() > elem.neighbor_ptr(f)->id()))
              {
                const Elem & face = face_builder(elem, f);

                for (auto s : face.side_index_range()) // Loop over face's edges
                  {
                    const Elem & side = side_builder(face, s);

                    // At this point, we just insert the node numbers
                    // again.  At the end we'll call sort and unique
                    // to make sure there are no duplicates
                    _graph[side.node_id(0)].push_back(side.node_id(1));
                    _graph[side.node_id(1)].push_back(side.node_id(0));
                  }
              }
        };

        for (auto & elem : _mesh.active_local_element_ptr_range())
          elem_to_graph(*elem);

        if (!_mesh.processor_id())
          for (auto & elem : _mesh.active_unpartitioned_element_ptr_range())
            elem_to_graph(*elem);

        _initialized = true;
        break;
      } // case 3

    default:
      libmesh_error_msg("At this time it is not possible to smooth a dimension " << _mesh.mesh_dimension() << "mesh.  Aborting...");
    }

  // Done building graph from local and/or unpartitioned elements.
  // Let's now allgather the graph so that it is available on all
  // processors for the actual smoothing operation.
  this->allgather_graph();

  // In 3D, it's possible for > 2 processor partitions to meet
  // at a single edge, while in 2D only 2 processor partitions
  // share an edge.  Therefore the allgather'd graph in 3D may
  // now have duplicate entries and we need to remove them so
  // they don't foul up the averaging algorithm employed by the
  // Laplace smoother.
  for (auto & id_vec : _graph)
    {
      // The std::unique algorithm removes duplicate *consecutive* elements from a range,
      // so it only makes sense to call it on a sorted range...
      std::sort(id_vec.begin(), id_vec.end());
      id_vec.erase(std::unique(id_vec.begin(), id_vec.end()), id_vec.end());
    }

} // init()

void LaplaceMeshSmoother::print_graph(std::ostream & out_stream) const
{
  for (auto i : index_range(_graph))
    {
      out_stream << i << ": ";
      std::copy(_graph[i].begin(),
                _graph[i].end(),
                std::ostream_iterator<unsigned>(out_stream, " "));
      out_stream << std::endl;
    }
}

void LaplaceMeshSmoother::allgather_graph()
{
  // The graph data structure is not well-suited for parallel communication,
  // so copy the graph into a single vector defined by:
  // NA A_0 A_1 ... A_{NA} | NB B_0 B_1 ... B_{NB} | NC C_0 C_1 ... C_{NC}
  // where:
  // * NA is the number of graph connections for node A
  // * A_0, A_1, etc. are the IDs connected to node A
  std::vector<dof_id_type> flat_graph;

  // Reserve at least enough space for each node to have zero entries
  flat_graph.reserve(_graph.size());

  for (const auto & id_vec : _graph)
    {
      // First push back the number of entries for this node
      flat_graph.push_back (cast_int<dof_id_type>(id_vec.size()));

      // Then push back all the IDs
      for (const auto & dof : id_vec)
        flat_graph.push_back(dof);
    }

  // // A copy of the flat graph (for printing only, delete me later)
  // std::vector<unsigned> copy_of_flat_graph(flat_graph);

  // Use the allgather routine to combine all the flat graphs on all processors
  _mesh.comm().allgather(flat_graph);

  // Now reconstruct _graph from the allgathered flat_graph.

  // // (Delete me later, the copy is just for printing purposes.)
  // std::vector<std::vector<unsigned >> copy_of_graph(_graph);

  // Make sure the old graph is cleared out
  _graph.clear();
  _graph.resize(_mesh.max_node_id());

  // Our current position in the allgather'd flat_graph
  std::size_t cursor=0;

  // There are max_node_id * n_processors entries to read in total
  for (processor_id_type p=0; p<_mesh.n_processors(); ++p)
    for (dof_id_type node_ctr=0; node_ctr<_mesh.max_node_id(); ++node_ctr)
      {
        // Read the number of entries for this node, move cursor
        std::size_t n_entries = flat_graph[cursor++];

        // Reserve space for that many more entries, then push back
        _graph[node_ctr].reserve(_graph[node_ctr].size() + n_entries);

        // Read all graph connections for this node, move the cursor each time
        // Note: there might be zero entries but that's fine
        for (std::size_t i=0; i<n_entries; ++i)
          _graph[node_ctr].push_back(flat_graph[cursor++]);
      }

  // // Print local graph to uniquely named file (debugging)
  // {
  //   // Generate unique filename for this processor
  //   std::ostringstream oss;
  //   oss << "graph_filename_" << _mesh.processor_id() << ".txt";
  //   std::ofstream graph_stream(oss.str().c_str());
  //
  //   // Print the local non-flat graph
  //   std::swap(_graph, copy_of_graph);
  //   print_graph(graph_stream);
  //
  //   // Print the (local) flat graph for verification
  //   for (const auto & dof : copy_of_flat_graph)
  //     graph_stream << dof << " ";
  //   graph_stream << "\n";
  //
  //   // Print the allgather'd grap for verification
  //   for (const auto & dof : flat_graph)
  //     graph_stream << dof << " ";
  //   graph_stream << "\n";
  //
  //   // Print the global non-flat graph
  //   std::swap(_graph, copy_of_graph);
  //   print_graph(graph_stream);
  // }
} // allgather_graph()

} // namespace libMesh
<|endoftext|>


<commit_before>/***************************************************************************
 *  @file       The code is for the exercises in C++ Primmer 5th Edition
 *  @author     Alan.W
 *  @date       23  DEC 2013
 *  @remark
 ***************************************************************************/
//!
//! Exercise 12.12:
//! Using the declarations of p and sp explain each of the following calls to
//! process. If the call is legal, explain what it does. If the call is illegal,
//! explain why:
//  See comments below.
//!

#include <iostream>
#include <vector>
#include <string>
#include <memory>

void process(std::shared_ptr<int> ptr)
{
    std::cout << "inside the process function:" << ptr.use_count() << "\n";
}

int main()
{
    auto p = new int();
    auto sp = std::make_shared<int>();

    /** @brief
     *  legal. Just copy sp which is a shared_ptr to process().
     */
    // process(sp);

    /** @brief
     *  illegale.plain pointer can not convert to smart pointer implicitly.
     */
    // process(new int());

    /** @brief
     *  illegale.plain pointer can not convert to smart pointer implicitly.
     */
    // process(p);

    /** @brief
     *  Legal. But it's a bad practice to do so.
     *  Because using smart pointer together with raw pointer could potentially
     * cause problems.
     *  For example double free as shown in #145.
     *
     *  Check issue #145 for detail, thx @endyul for reporting
     */
    // process(std::shared_ptr<int>(p));

    return 0;
}
<commit_msg>Update ex12_12.cpp<commit_after>//!
//! Exercise 12.12:
//! Using the declarations of p and sp explain each of the following calls to
//! process. If the call is legal, explain what it does. If the call is illegal,
//! explain why:
//!

#include <iostream>
#include <memory>

using namespace std;

void process(shared_ptr<int> ptr)
{
    cout<<"inside the process function: "<<ptr.use_count()<<endl;
}

int main()
{
    auto p=new int();
    auto sp=make_shared<Int>();

    //legal. Just copy sp which is a shared_ptr to process().
    process(sp);

    //illegal. Plain pointer can not convert to smart pointer implicitly.
    process(new int());

    //illegal. Plain pointer can not convert to smart pointer implicitly.
    process(p);

    //It's a bad practice to do so.
    //Because using smart pointer together with raw pointer could
    //potentially cause problems.
    process(shared_ptr<int>(p));
}
<|endoftext|>


<commit_before><commit_msg>Fix international domain printing bug.<commit_after><|endoftext|>


<commit_before>#include <stdio.h>
#include <fcntl.h>

#include "gtest/gtest.h"

class OpenTest : public testing::Test {

protected:
  OpenTest(): fd_(-1), path_("/tmp/apue.log") {}

  virtual void SetUp() {
    fd_ = open(path_, O_RDONLY | O_CREAT);
    printf("-- %d--> create %s\n", fd_, path_);
  }

  virtual void TearDown() {
    int r = close(fd_);
    printf("-- %d--> close %s\n", r, path_);
  }

  int fd_;
  const char* path_;
};

TEST_F(OpenTest, TestReadOnly) {
  int fd = open(path_, O_RDONLY);
  printf("-- fd = %d read only\n", fd);
  close(fd);
}

TEST_F(OpenTest, TestWriteOnly) {
  int fd = open(path_, O_WRONLY);
  printf("-- fd = %d write only\n", fd);
  close(fd);
}

TEST_F(OpenTest, TestRDWR) {
  int fd = open(path_, O_RDWR);
  printf("-- fd = %d read writer\n", fd);
  close(fd);
}

TEST_F(OpenTest, TestEXEC) {
  int fd = open(path_, O_CREAT);
  printf("-- fd = %d, create\n", fd);
  close(fd);
}

int main(int argc, char* argv[]) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>learning & fighting<commit_after>#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>

#include "gtest/gtest.h"

class OpenTest : public testing::Test {

protected:
  OpenTest(): fd_(-1), path_("/tmp/apue.log") {}

  virtual void SetUp() {
    fd_ = open(path_, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    printf("-- %d--> create %s\n", fd_, path_);
    int r = close(fd_);
    printf("-- %d--> close %s\n", r, path_);
  }

  virtual void TearDown() {
    printf("-- --> tear down ...\n");
  }

  int fd_;
  const char* path_;
};

TEST_F(OpenTest, TestReadOnly) {
  int fd = open(path_, O_RDONLY);
  printf("-- fd = %d read only\n", fd);
  EXPECT_EQ(3, fd);
  close(fd);
}

TEST_F(OpenTest, TestWriteOnly) {
  int fd = open(path_, O_WRONLY);
  printf("-- fd = %d write only\n", fd);
  EXPECT_EQ(3, fd);
  close(fd);
}

TEST_F(OpenTest, TestRDWR) {
  int fd = open(path_, O_RDWR);
  printf("-- fd = %d read write\n", fd);
  EXPECT_EQ(3, fd);
  close(fd);
}

// opensuse not surpport the O_EXEC option.
//TEST_F(OpenTest, TestEXEC) {
//  int fd = open(path_, O_EXEC);
//  printf("-- fd = %d, exec\n", fd);
//  close(fd);
//}

// opensuse no surport the O_SEARCH option.
//TEST_F(OpenTest, TestSearch) {
//  int fd = open(path_, O_SEARCH);
//  printf("-- fd = %d, search\n", fd);
//  close(fd);
//}

int main(int argc, char* argv[]) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/*************************************************************************/
/*  json.cpp                                                             */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "json.h"
#include "print_string.h"

const char * JSON::tk_name[TK_MAX] = {
	"'{'",
	"'}'",
	"'['",
	"']'",
	"identifier",
	"string",
	"number",
	"':'",
	"','",
	"EOF",
};

String JSON::_print_var(const Variant& p_var) {

	switch(p_var.get_type()) {

		case Variant::NIL: return "null";
		case Variant::BOOL: return p_var.operator bool() ? "true": "false";
		case Variant::INT: return itos(p_var);
		case Variant::REAL: return rtos(p_var);
		case Variant::POOL_INT_ARRAY:
		case Variant::POOL_REAL_ARRAY:
		case Variant::POOL_STRING_ARRAY:
		case Variant::ARRAY: {

			String s = "[";
			Array a = p_var;
			for(int i=0;i<a.size();i++) {
				if (i>0)
					s+=", ";
				s+=_print_var(a[i]);
			}
			s+="]";
			return s;
		};
		case Variant::DICTIONARY: {

			String s = "{";
			Dictionary d = p_var;
			List<Variant> keys;
			d.get_key_list(&keys);

			for (List<Variant>::Element *E=keys.front();E;E=E->next()) {

				if (E!=keys.front())
					s+=", ";
				s+=_print_var(String(E->get()));
				s+=":";
				s+=_print_var(d[E->get()]);
			}

			s+="}";
			return s;
		};
		default: return "\""+String(p_var).json_escape()+"\"";

	}

}

String JSON::print(const Variant& p_var) {

	return _print_var(p_var);
}

Error JSON::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_token,int &line,String &r_err_str) {

	while (true) {
		switch(p_str[idx]) {

			case '\n': {

				line++;
				idx++;
				break;
			};
			case 0: {
				r_token.type=TK_EOF;
				return OK;
			} break;
			case '{': {

				r_token.type=TK_CURLY_BRACKET_OPEN;
				idx++;
				return OK;
			};
			case '}': {

				r_token.type=TK_CURLY_BRACKET_CLOSE;
				idx++;
				return OK;
			};
			case '[': {

				r_token.type=TK_BRACKET_OPEN;
				idx++;
				return OK;
			};
			case ']': {

				r_token.type=TK_BRACKET_CLOSE;
				idx++;
				return OK;
			};
			case ':': {

				r_token.type=TK_COLON;
				idx++;
				return OK;
			};
			case ',': {

				r_token.type=TK_COMMA;
				idx++;
				return OK;
			};
			case '"': {

				idx++;
				String str;
				while(true) {
					if (p_str[idx]==0) {
						r_err_str="Unterminated String";
						return ERR_PARSE_ERROR;
					} else if (p_str[idx]=='"') {
						idx++;
						break;
					} else if (p_str[idx]=='\\') {
						//escaped characters...
						idx++;
						CharType next = p_str[idx];
						if (next==0) {
							r_err_str="Unterminated String";
							return  ERR_PARSE_ERROR;
						}
						CharType res=0;

						switch(next) {

							case 'b': res=8; break;
							case 't': res=9; break;
							case 'n': res=10; break;
							case 'f': res=12; break;
							case 'r': res=13; break;
							case 'u': {
								//hexnumbarh - oct is deprecated

								for(int j=0;j<4;j++) {
									CharType c = p_str[idx+j+1];
									if (c==0) {
										r_err_str="Unterminated String";
										return ERR_PARSE_ERROR;
									}
									if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) {

										r_err_str="Malformed hex constant in string";
										return ERR_PARSE_ERROR;
									}
									CharType v;
									if (c>='0' && c<='9') {
										v=c-'0';
									} else if (c>='a' && c<='f') {
										v=c-'a';
										v+=10;
									} else if (c>='A' && c<='F') {
										v=c-'A';
										v+=10;
									} else {
										ERR_PRINT("BUG");
										v=0;
									}

									res<<=4;
									res|=v;

								}
								idx+=4; //will add at the end anyway

							} break;
							//case '\"': res='\"'; break;
							//case '\\': res='\\'; break;
							//case '/': res='/'; break;
							default: {
								res = next;
								//r_err_str="Invalid escape sequence";
								//return ERR_PARSE_ERROR;
							} break;
						}

						str+=res;

					} else {
						if (p_str[idx]=='\n')
							line++;
						str+=p_str[idx];
					}
					idx++;
				}

				r_token.type=TK_STRING;
				r_token.value=str;
				return OK;

			} break;
			default: {

				if (p_str[idx]<=32) {
					idx++;
					break;
				}

				if (p_str[idx]=='-' || (p_str[idx]>='0' && p_str[idx]<='9')) {
					//a number
					const CharType *rptr;
					double number = String::to_double(&p_str[idx],&rptr);
					idx+=(rptr - &p_str[idx]);
					r_token.type=TK_NUMBER;
					r_token.value=number;
					return OK;

				} else if ((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {

					String id;

					while((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {

						id+=p_str[idx];
						idx++;
					}

					r_token.type=TK_IDENTIFIER;
					r_token.value=id;
					return OK;
				} else {
					r_err_str="Unexpected character.";
					return ERR_PARSE_ERROR;
				}
			}

		}
	}

	return ERR_PARSE_ERROR;
}

Error JSON::_parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) {

	if (token.type==TK_CURLY_BRACKET_OPEN) {

		Dictionary d;
		Error err = _parse_object(d,p_str,index,p_len,line,r_err_str);
		if (err)
			return err;
		value=d;
		return OK;
	} else if (token.type==TK_BRACKET_OPEN) {

		Array a;
		Error err = _parse_array(a,p_str,index,p_len,line,r_err_str);
		if (err)
			return err;
		value=a;
		return OK;

	} else if (token.type==TK_IDENTIFIER) {

		String id = token.value;
		if (id=="true")
			value=true;
		else if (id=="false")
			value=false;
		else if (id=="null")
			value=Variant();
		else {
			r_err_str="Expected 'true','false' or 'null', got '"+id+"'.";
			return ERR_PARSE_ERROR;
		}
		return OK;

	} else if (token.type==TK_NUMBER) {

		value=token.value;
		return OK;
	} else if (token.type==TK_STRING) {

		value=token.value;
		return OK;
	} else {
		r_err_str="Expected value, got "+String(tk_name[token.type])+".";
		return ERR_PARSE_ERROR;
	}

	return ERR_PARSE_ERROR;
}

Error JSON::_parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) {

	Token token;
	bool need_comma=false;

	while(index<p_len) {

		Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
		if (err!=OK)
			return err;

		if (token.type==TK_BRACKET_CLOSE) {

			return OK;
		}

		if (need_comma) {

			if (token.type!=TK_COMMA) {

				r_err_str="Expected ','";
				return ERR_PARSE_ERROR;
			} else {
				need_comma=false;
				continue;
			}
		}

		Variant v;
		err = _parse_value(v,token,p_str,index,p_len,line,r_err_str);
		if (err)
			return err;

		array.push_back(v);
		need_comma=true;

	}

	return OK;

}

Error JSON::_parse_object(Dictionary &object,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) {

	bool at_key=true;
	String key;
	Token token;
	bool need_comma=false;

	while(index<p_len) {

		if (at_key) {

			Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
			if (err!=OK)
				return err;

			if (token.type==TK_CURLY_BRACKET_CLOSE) {

				return OK;
			}

			if (need_comma) {

				if (token.type!=TK_COMMA) {

					r_err_str="Expected '}' or ','";
					return ERR_PARSE_ERROR;
				} else {
					need_comma=false;
					continue;
				}
			}

			if (token.type!=TK_STRING) {

				r_err_str="Expected key";
				return ERR_PARSE_ERROR;
			}

			key=token.value;
			err = _get_token(p_str,index,p_len,token,line,r_err_str);
			if (err!=OK)
				return err;
			if (token.type!=TK_COLON) {

				r_err_str="Expected ':'";
				return ERR_PARSE_ERROR;
			}
			at_key=false;
		} else {

			Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
			if (err!=OK)
				return err;

			Variant v;
			err = _parse_value(v,token,p_str,index,p_len,line,r_err_str);
			if (err)
				return err;
			object[key]=v;
			need_comma=true;
			at_key=true;
		}
	}

	return OK;
}

Error JSON::parse(const String& p_json, Variant &r_ret, String &r_err_str, int &r_err_line) {

	const CharType *str = p_json.ptr();
	int idx = 0;
	int len = p_json.length();
	Token token;
	r_err_line=0;
	String aux_key;

	Error err = _get_token(str,idx,len,token,r_err_line,r_err_str);
	if (err)
		return err;

	err = _parse_value(r_ret,token,str,idx,len,r_err_line,r_err_str);

	return err;

}

<commit_msg>Fix error while JSON::parse with empty string<commit_after>/*************************************************************************/
/*  json.cpp                                                             */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "json.h"
#include "print_string.h"

const char * JSON::tk_name[TK_MAX] = {
	"'{'",
	"'}'",
	"'['",
	"']'",
	"identifier",
	"string",
	"number",
	"':'",
	"','",
	"EOF",
};

String JSON::_print_var(const Variant& p_var) {

	switch(p_var.get_type()) {

		case Variant::NIL: return "null";
		case Variant::BOOL: return p_var.operator bool() ? "true": "false";
		case Variant::INT: return itos(p_var);
		case Variant::REAL: return rtos(p_var);
		case Variant::POOL_INT_ARRAY:
		case Variant::POOL_REAL_ARRAY:
		case Variant::POOL_STRING_ARRAY:
		case Variant::ARRAY: {

			String s = "[";
			Array a = p_var;
			for(int i=0;i<a.size();i++) {
				if (i>0)
					s+=", ";
				s+=_print_var(a[i]);
			}
			s+="]";
			return s;
		};
		case Variant::DICTIONARY: {

			String s = "{";
			Dictionary d = p_var;
			List<Variant> keys;
			d.get_key_list(&keys);

			for (List<Variant>::Element *E=keys.front();E;E=E->next()) {

				if (E!=keys.front())
					s+=", ";
				s+=_print_var(String(E->get()));
				s+=":";
				s+=_print_var(d[E->get()]);
			}

			s+="}";
			return s;
		};
		default: return "\""+String(p_var).json_escape()+"\"";

	}

}

String JSON::print(const Variant& p_var) {

	return _print_var(p_var);
}

Error JSON::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_token,int &line,String &r_err_str) {

	while (p_len > 0) {
		switch(p_str[idx]) {

			case '\n': {

				line++;
				idx++;
				break;
			};
			case 0: {
				r_token.type=TK_EOF;
				return OK;
			} break;
			case '{': {

				r_token.type=TK_CURLY_BRACKET_OPEN;
				idx++;
				return OK;
			};
			case '}': {

				r_token.type=TK_CURLY_BRACKET_CLOSE;
				idx++;
				return OK;
			};
			case '[': {

				r_token.type=TK_BRACKET_OPEN;
				idx++;
				return OK;
			};
			case ']': {

				r_token.type=TK_BRACKET_CLOSE;
				idx++;
				return OK;
			};
			case ':': {

				r_token.type=TK_COLON;
				idx++;
				return OK;
			};
			case ',': {

				r_token.type=TK_COMMA;
				idx++;
				return OK;
			};
			case '"': {

				idx++;
				String str;
				while(true) {
					if (p_str[idx]==0) {
						r_err_str="Unterminated String";
						return ERR_PARSE_ERROR;
					} else if (p_str[idx]=='"') {
						idx++;
						break;
					} else if (p_str[idx]=='\\') {
						//escaped characters...
						idx++;
						CharType next = p_str[idx];
						if (next==0) {
							r_err_str="Unterminated String";
							return  ERR_PARSE_ERROR;
						}
						CharType res=0;

						switch(next) {

							case 'b': res=8; break;
							case 't': res=9; break;
							case 'n': res=10; break;
							case 'f': res=12; break;
							case 'r': res=13; break;
							case 'u': {
								//hexnumbarh - oct is deprecated

								for(int j=0;j<4;j++) {
									CharType c = p_str[idx+j+1];
									if (c==0) {
										r_err_str="Unterminated String";
										return ERR_PARSE_ERROR;
									}
									if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) {

										r_err_str="Malformed hex constant in string";
										return ERR_PARSE_ERROR;
									}
									CharType v;
									if (c>='0' && c<='9') {
										v=c-'0';
									} else if (c>='a' && c<='f') {
										v=c-'a';
										v+=10;
									} else if (c>='A' && c<='F') {
										v=c-'A';
										v+=10;
									} else {
										ERR_PRINT("BUG");
										v=0;
									}

									res<<=4;
									res|=v;

								}
								idx+=4; //will add at the end anyway

							} break;
							//case '\"': res='\"'; break;
							//case '\\': res='\\'; break;
							//case '/': res='/'; break;
							default: {
								res = next;
								//r_err_str="Invalid escape sequence";
								//return ERR_PARSE_ERROR;
							} break;
						}

						str+=res;

					} else {
						if (p_str[idx]=='\n')
							line++;
						str+=p_str[idx];
					}
					idx++;
				}

				r_token.type=TK_STRING;
				r_token.value=str;
				return OK;

			} break;
			default: {

				if (p_str[idx]<=32) {
					idx++;
					break;
				}

				if (p_str[idx]=='-' || (p_str[idx]>='0' && p_str[idx]<='9')) {
					//a number
					const CharType *rptr;
					double number = String::to_double(&p_str[idx],&rptr);
					idx+=(rptr - &p_str[idx]);
					r_token.type=TK_NUMBER;
					r_token.value=number;
					return OK;

				} else if ((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {

					String id;

					while((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {

						id+=p_str[idx];
						idx++;
					}

					r_token.type=TK_IDENTIFIER;
					r_token.value=id;
					return OK;
				} else {
					r_err_str="Unexpected character.";
					return ERR_PARSE_ERROR;
				}
			}

		}
	}

	return ERR_PARSE_ERROR;
}

Error JSON::_parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) {

	if (token.type==TK_CURLY_BRACKET_OPEN) {

		Dictionary d;
		Error err = _parse_object(d,p_str,index,p_len,line,r_err_str);
		if (err)
			return err;
		value=d;
		return OK;
	} else if (token.type==TK_BRACKET_OPEN) {

		Array a;
		Error err = _parse_array(a,p_str,index,p_len,line,r_err_str);
		if (err)
			return err;
		value=a;
		return OK;

	} else if (token.type==TK_IDENTIFIER) {

		String id = token.value;
		if (id=="true")
			value=true;
		else if (id=="false")
			value=false;
		else if (id=="null")
			value=Variant();
		else {
			r_err_str="Expected 'true','false' or 'null', got '"+id+"'.";
			return ERR_PARSE_ERROR;
		}
		return OK;

	} else if (token.type==TK_NUMBER) {

		value=token.value;
		return OK;
	} else if (token.type==TK_STRING) {

		value=token.value;
		return OK;
	} else {
		r_err_str="Expected value, got "+String(tk_name[token.type])+".";
		return ERR_PARSE_ERROR;
	}

	return ERR_PARSE_ERROR;
}

Error JSON::_parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) {

	Token token;
	bool need_comma=false;

	while(index<p_len) {

		Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
		if (err!=OK)
			return err;

		if (token.type==TK_BRACKET_CLOSE) {

			return OK;
		}

		if (need_comma) {

			if (token.type!=TK_COMMA) {

				r_err_str="Expected ','";
				return ERR_PARSE_ERROR;
			} else {
				need_comma=false;
				continue;
			}
		}

		Variant v;
		err = _parse_value(v,token,p_str,index,p_len,line,r_err_str);
		if (err)
			return err;

		array.push_back(v);
		need_comma=true;

	}

	return OK;

}

Error JSON::_parse_object(Dictionary &object,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) {

	bool at_key=true;
	String key;
	Token token;
	bool need_comma=false;

	while(index<p_len) {

		if (at_key) {

			Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
			if (err!=OK)
				return err;

			if (token.type==TK_CURLY_BRACKET_CLOSE) {

				return OK;
			}

			if (need_comma) {

				if (token.type!=TK_COMMA) {

					r_err_str="Expected '}' or ','";
					return ERR_PARSE_ERROR;
				} else {
					need_comma=false;
					continue;
				}
			}

			if (token.type!=TK_STRING) {

				r_err_str="Expected key";
				return ERR_PARSE_ERROR;
			}

			key=token.value;
			err = _get_token(p_str,index,p_len,token,line,r_err_str);
			if (err!=OK)
				return err;
			if (token.type!=TK_COLON) {

				r_err_str="Expected ':'";
				return ERR_PARSE_ERROR;
			}
			at_key=false;
		} else {

			Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
			if (err!=OK)
				return err;

			Variant v;
			err = _parse_value(v,token,p_str,index,p_len,line,r_err_str);
			if (err)
				return err;
			object[key]=v;
			need_comma=true;
			at_key=true;
		}
	}

	return OK;
}

Error JSON::parse(const String& p_json, Variant &r_ret, String &r_err_str, int &r_err_line) {

	const CharType *str = p_json.ptr();
	int idx = 0;
	int len = p_json.length();
	Token token;
	r_err_line=0;
	String aux_key;

	Error err = _get_token(str,idx,len,token,r_err_line,r_err_str);
	if (err)
		return err;

	err = _parse_value(r_ret,token,str,idx,len,r_err_line,r_err_str);

	return err;

}

<|endoftext|>


<commit_before>#pragma once

#include "../util.hpp"

template<int M>
class Cyclic {
  using ll = long long;
  int n;
  static ll inv(ll a, ll p) { return (a == 1 ? 1 : (1 - p * inv(p%a, a)) / a + p); }
public:
  Cyclic () : n(0) {;}
  Cyclic (int m) : n(m) {
    if (n >= M) n %= M;
    else if (n < 0) n = (n % M + M) % M;
  }
  operator int() const { return n; }
  bool operator==(const Cyclic &a) const { return n == a.n; }
  Cyclic operator+=(const Cyclic &a) { n += a.n; if (n >= M) n -= M; return *this; }
  Cyclic operator-=(const Cyclic &a) { n -= a.n; if (n < 0) n += M; return *this; }
  Cyclic operator*=(const Cyclic &a) { n = (ll(n) * a.n) % M; return *this; }
  Cyclic operator+(const Cyclic &a) const { Cyclic res = *this; return res += a; }
  Cyclic operator-(const Cyclic &a) const { Cyclic res = *this; return res -= a; }
  Cyclic operator*(const Cyclic &a) const { Cyclic res = *this; return res *= a; }
  Cyclic operator/(const Cyclic &a) const { return *this * Cyclic<M>(inv(a, M)); }
  Cyclic operator^(int n) const {
    if (n == 0) return Cyclic(1);
    const Cyclic a = *this;
    Cyclic res = (a * a) ^ (n / 2);
    return n % 2 ? res * a : res;
  }
};

template<int M> Cyclic<M> fact(int n, bool sw = true) {
  static vector<Cyclic<M>> v1 = {1}, v2 = {1};
  if (n >= (int)v1.size()) {
    const int from = v1.size(), to = n + 1024;
    v1.reserve(to);
    v2.reserve(to);
    for (int i = from; i < to; ++i) {
      v1.push_back(v1.back() * Cyclic<M>(i));
      v2.push_back(v2.back() / Cyclic<M>(i));
    }
  }
  return sw ? v1[n] : v2[n];
}

template<int M> Cyclic<M> comb(int a, int b) {
  return fact<M>(a, true) * fact<M>(b, false) * fact<M>(a-b, false);
}

const int mod = 1000000007;
using Mod = Cyclic<mod>;
<commit_msg>add verifier of mod<commit_after>#pragma once

#include "../util.hpp"

template<int M>
class Cyclic {
  using ll = long long;
  int n;
  static ll inv(ll a, ll p) { return (a == 1 ? 1 : (1 - p * inv(p%a, a)) / a + p); }
public:
  Cyclic () : n(0) {;}
  Cyclic (int m) : n(m) {
    if (n >= M) n %= M;
    else if (n < 0) n = (n % M + M) % M;
  }
  operator int() const { return n; }
  bool operator==(const Cyclic &a) const { return n == a.n; }
  Cyclic operator+=(const Cyclic &a) { n += a.n; if (n >= M) n -= M; return *this; }
  Cyclic operator-=(const Cyclic &a) { n -= a.n; if (n < 0) n += M; return *this; }
  Cyclic operator*=(const Cyclic &a) { n = (ll(n) * a.n) % M; return *this; }
  Cyclic operator+(const Cyclic &a) const { Cyclic res = *this; return res += a; }
  Cyclic operator-(const Cyclic &a) const { Cyclic res = *this; return res -= a; }
  Cyclic operator*(const Cyclic &a) const { Cyclic res = *this; return res *= a; }
  Cyclic operator/(const Cyclic &a) const { return *this * Cyclic<M>(inv(a, M)); }
  Cyclic operator^(int n) const {
    if (n == 0) return Cyclic(1);
    const Cyclic a = *this;
    Cyclic res = (a * a) ^ (n / 2);
    return n % 2 ? res * a : res;
  }
};

template<int M> Cyclic<M> fact(int n, bool sw = true) {
  static vector<Cyclic<M>> v1 = {1}, v2 = {1};
  if (n >= (int)v1.size()) {
    const int from = v1.size(), to = n + 1024;
    v1.reserve(to);
    v2.reserve(to);
    for (int i = from; i < to; ++i) {
      v1.push_back(v1.back() * Cyclic<M>(i));
      v2.push_back(v2.back() / Cyclic<M>(i));
    }
  }
  return sw ? v1[n] : v2[n];
}

template<int M> Cyclic<M> comb(int a, int b) {
  return fact<M>(a, true) * fact<M>(b, false) * fact<M>(a-b, false);
}

const int mod = 1000000007;
using Mod = Cyclic<mod>;

// Verified : ABC 003D
/*
int main() {
  int R, C, X, Y, D, L;
  cin >> R >> C >> X >> Y >> D >> L;
  Mod a = Mod(R - X + 1) * Mod(C - Y + 1);
  Mod b = solve(X, Y, D, L);
  b -= solve(X-1, Y, D, L) * Mod(2);
  b -= solve(X, Y-1, D, L) * Mod(2);
  b += solve(X-2, Y, D, L);
  b += solve(X, Y-2, D, L);
  b += solve(X-1, Y-1, D, L) * Mod(4);
  b -= solve(X-2, Y-1, D, L) * Mod(2);
  b -= solve(X-1, Y-2, D, L) * Mod(2);
  b += solve(X-2, Y-2, D, L);
  cout << a * b << endl;
  return 0;
}
*/
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: fuline.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: obo $ $Date: 2004-01-20 12:03:02 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SD_FU_LINE_HXX
#define SD_FU_LINE_HXX

#ifndef SD_FU_POOR_HXX
#include "fupoor.hxx"
#endif

namespace sd {

class FuLine
    : public FuPoor
{
public:
    TYPEINFO();

    FuLine (
        ViewShell* pViewSh,
        ::sd::Window* pWin,
        ::sd::View* pView,
        SdDrawDocument* pDoc,
        SfxRequest& rReq);
    virtual ~FuLine (void) {}

    virtual void Activate() {}
    virtual void Deactivate() {}
};

} // end of namespace sd

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.2.562); FILE MERGED 2005/09/05 13:23:07 rt 1.2.562.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: fuline.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 05:34:56 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *
 ************************************************************************/

#ifndef SD_FU_LINE_HXX
#define SD_FU_LINE_HXX

#ifndef SD_FU_POOR_HXX
#include "fupoor.hxx"
#endif

namespace sd {

class FuLine
    : public FuPoor
{
public:
    TYPEINFO();

    FuLine (
        ViewShell* pViewSh,
        ::sd::Window* pWin,
        ::sd::View* pView,
        SdDrawDocument* pDoc,
        SfxRequest& rReq);
    virtual ~FuLine (void) {}

    virtual void Activate() {}
    virtual void Deactivate() {}
};

} // end of namespace sd

#endif

<|endoftext|>


<commit_before>#include "../include/graph/bfs01.cpp"

#define REP(i,n) for(int i=0;i<(n);++i)

int H, W, A;
string str[128];
int getId(int i, int j, int a, int b, int dir) {
  return i*W*(A+1)*(A+1)*4 + j*(A+1)*(A+1)*4 + a*(A+1)*4 + b*4 + dir;
}

int main() {
  cin >> H >> W >> A;
  REP(i,H) cin >> str[i];
  int starty, startx, goaly, goalx;
  REP(i,H) REP(j,W) {
    if (str[i][j] == 'S') starty = i, startx = j;
    if (str[i][j] == 'G') goaly = i, goalx = j;
  }
  Graph<int> g(H*W*(A+1)*(A+1)*4);
  REP(i,H-1) REP(j,W) REP(a,A+1) REP(b,A+1) {
    if (str[i+1][j] != '#')
      add_edge(g, getId(i,j,a,b,3), getId(i+1,j,a,b,3), 0);
    if (str[i+1][j] == '.') {
      if (a>0) add_edge(g, getId(i,j,a,b,3), getId(i+1,j,a-1,b,0), 1);
      if (b>0) add_edge(g, getId(i,j,a,b,3), getId(i+1,j,a,b-1,2), 1);
    }
    if (str[i][j] == '.' || str[i][j] == 'G') {
      add_edge(g, getId(i+1,j,a,b,1), getId(i,j,a,b,1), 0);
      if (a>0) add_edge(g, getId(i+1,j,a,b,1), getId(i,j,a-1,b,2), 1);
      if (b>0) add_edge(g, getId(i+1,j,a,b,1), getId(i,j,a,b-1,0), 1);
    }
  }
  REP(i,H) REP(j,W-1) REP(a,A+1) REP(b,A+1) {
    if (str[i][j+1] != '#')
      add_edge(g, getId(i,j,a,b,0), getId(i,j+1,a,b,0), 0);
    if (str[i][j+1] == '.') {
      if (a>0) add_edge(g, getId(i,j,a,b,0), getId(i,j+1,a-1,b,3), 1);
      if (b>0) add_edge(g, getId(i,j,a,b,0), getId(i,j+1,a,b-1,1), 1);
    }
    if (str[i][j] != '#')
      add_edge(g, getId(i,j+1,a,b,2), getId(i,j,a,b,2), 0);
    if (str[i][j] == '.') {
      if (a>0) add_edge(g, getId(i,j+1,a,b,2), getId(i,j,a-1,b,1), 1);
      if (b>0) add_edge(g, getId(i,j+1,a,b,2), getId(i,j,a,b-1,3), 1);
    }
  }
  vector<int> d = bfs01(g, getId(starty,startx,A,A,3));
  int res = inf<int>;
  REP(a,A+1) REP(b,A+1) REP(dir,4)
    res = min(res, d[getId(goaly,goalx,a,b,dir)]);
  cout << (res == inf<int> ? -1 : res) << endl;
  return 0;
}
<commit_msg>bug fix<commit_after>#include "../include/graph/bfs01.cpp"

#define REP(i,n) for(int i=0;i<(n);++i)

int H, W, A;
string str[128];
int getId(int i, int j, int a, int b, int dir) {
  return i*W*(A+1)*(A+1)*4 + j*(A+1)*(A+1)*4 + a*(A+1)*4 + b*4 + dir;
}

int main() {
  cin >> H >> W >> A;
  REP(i,H) cin >> str[i];
  int starty = -1, startx = -1, goaly = -1, goalx = -1;
  REP(i,H) REP(j,W) {
    if (str[i][j] == 'S') starty = i, startx = j;
    if (str[i][j] == 'G') goaly = i, goalx = j;
  }
  Graph<int> g(H*W*(A+1)*(A+1)*4);
  REP(i,H-1) REP(j,W) REP(a,A+1) REP(b,A+1) {
    if (str[i+1][j] != '#')
      add_edge(g, getId(i,j,a,b,3), getId(i+1,j,a,b,3), 0);
    if (str[i+1][j] == '.') {
      if (a>0) add_edge(g, getId(i,j,a,b,3), getId(i+1,j,a-1,b,0), 1);
      if (b>0) add_edge(g, getId(i,j,a,b,3), getId(i+1,j,a,b-1,2), 1);
    }
    if (str[i][j] == '.' || str[i][j] == 'G') {
      add_edge(g, getId(i+1,j,a,b,1), getId(i,j,a,b,1), 0);
      if (a>0) add_edge(g, getId(i+1,j,a,b,1), getId(i,j,a-1,b,2), 1);
      if (b>0) add_edge(g, getId(i+1,j,a,b,1), getId(i,j,a,b-1,0), 1);
    }
  }
  REP(i,H) REP(j,W-1) REP(a,A+1) REP(b,A+1) {
    if (str[i][j+1] != '#')
      add_edge(g, getId(i,j,a,b,0), getId(i,j+1,a,b,0), 0);
    if (str[i][j+1] == '.') {
      if (a>0) add_edge(g, getId(i,j,a,b,0), getId(i,j+1,a-1,b,3), 1);
      if (b>0) add_edge(g, getId(i,j,a,b,0), getId(i,j+1,a,b-1,1), 1);
    }
    if (str[i][j] != '#')
      add_edge(g, getId(i,j+1,a,b,2), getId(i,j,a,b,2), 0);
    if (str[i][j] == '.') {
      if (a>0) add_edge(g, getId(i,j+1,a,b,2), getId(i,j,a-1,b,1), 1);
      if (b>0) add_edge(g, getId(i,j+1,a,b,2), getId(i,j,a,b-1,3), 1);
    }
  }
  vector<int> d = bfs01(g, getId(starty,startx,A,A,3));
  int res = inf<int>;
  REP(a,A+1) REP(b,A+1) REP(dir,4)
    res = min(res, d[getId(goaly,goalx,a,b,dir)]);
  cout << (res == inf<int> ? -1 : res) << endl;
  return 0;
}
<|endoftext|>


<commit_before>#include "stdafx.h"

Triangle triangle;

static InputElement elements[] = {
	CInputElement("POSITION", SF_R32G32B32_FLOAT, 0),
	CInputElement("COLOR", SF_R32G32B32_FLOAT, 12),
};

struct Vertex {
	Vec3 pos;
	Vec3 color;
};

static Vertex vertices[] = {
	{ Vec3(0, 1, 0), Vec3(1, 1, 0) },
	{ Vec3(-1, -1, 0), Vec3(0, 1, 1) },
	{ Vec3(1, -1, 0), Vec3(1, 0, 1) },
};
static AFIndex indices[] = {
	0, 1, 2
};

void Triangle::Draw()
{
	if (!vbo) {
		return;
	}
	afSetPipeline(pipelineState, rootSignature);
	afSetVertexBuffer(vbo, sizeof(Vertex));
	afSetIndexBuffer(ibo);
	Mat matWorld[] = {
		q2m(Quat(Vec3(0, 0, 1), (float)GetTime())) * translate(-1, 0, 0),
		q2m(Quat(Vec3(0, 1, 0), (float)GetTime())),
		q2m(Quat(Vec3(1, 0, 0), (float)GetTime())) * translate(1, 0, 0)
	};
	Mat matProj = ortho(-2, 2, -2, 2, 0.001f, 10.0f);
	Mat matView = lookatLH(Vec3(0, 0, -1), Vec3(0, 0, 0), Vec3(0, 1, 0));
	for (int i = 0; i < dimof(matWorld); i++) {
		Mat m = matWorld[i] * matView * matProj;
		afBindBufferToBindingPoint(&m, sizeof(m), 0);
		afDrawIndexed(PT_TRIANGLELIST, 3);
	}
}

void Triangle::Create()
{
	vbo = afCreateVertexBuffer(sizeof(Vertex) * 3, vertices);
	ibo = afCreateIndexBuffer(indices, _countof(indices));
	vbo->SetName(L"Triangle vertex bugger");
	ibo->SetName(L"Triangle index bugger");
	pipelineState = afCreatePSO("solid", elements, dimof(elements), BM_NONE, DSM_DEPTH_ENABLE, CM_DISABLE, rootSignature, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
}

void Triangle::Destroy()
{
	vbo.Reset();
	ibo.Reset();
	rootSignature.Reset();
	pipelineState.Reset();
}
<commit_msg>Fix typo.<commit_after>#include "stdafx.h"

Triangle triangle;

static InputElement elements[] = {
	CInputElement("POSITION", SF_R32G32B32_FLOAT, 0),
	CInputElement("COLOR", SF_R32G32B32_FLOAT, 12),
};

struct Vertex {
	Vec3 pos;
	Vec3 color;
};

static Vertex vertices[] = {
	{ Vec3(0, 1, 0), Vec3(1, 1, 0) },
	{ Vec3(-1, -1, 0), Vec3(0, 1, 1) },
	{ Vec3(1, -1, 0), Vec3(1, 0, 1) },
};
static AFIndex indices[] = {
	0, 1, 2
};

void Triangle::Draw()
{
	if (!vbo) {
		return;
	}
	afSetPipeline(pipelineState, rootSignature);
	afSetVertexBuffer(vbo, sizeof(Vertex));
	afSetIndexBuffer(ibo);
	Mat matWorld[] = {
		q2m(Quat(Vec3(0, 0, 1), (float)GetTime())) * translate(-1, 0, 0),
		q2m(Quat(Vec3(0, 1, 0), (float)GetTime())),
		q2m(Quat(Vec3(1, 0, 0), (float)GetTime())) * translate(1, 0, 0)
	};
	Mat matProj = ortho(-2, 2, -2, 2, 0.001f, 10.0f);
	Mat matView = lookatLH(Vec3(0, 0, -1), Vec3(0, 0, 0), Vec3(0, 1, 0));
	for (int i = 0; i < dimof(matWorld); i++) {
		Mat m = matWorld[i] * matView * matProj;
		afBindBufferToBindingPoint(&m, sizeof(m), 0);
		afDrawIndexed(PT_TRIANGLELIST, 3);
	}
}

void Triangle::Create()
{
	vbo = afCreateVertexBuffer(sizeof(Vertex) * 3, vertices);
	ibo = afCreateIndexBuffer(indices, _countof(indices));
	vbo->SetName(L"Triangle vertex buffer");
	ibo->SetName(L"Triangle index buffer");
	pipelineState = afCreatePSO("solid", elements, dimof(elements), BM_NONE, DSM_DEPTH_ENABLE, CM_DISABLE, rootSignature, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
}

void Triangle::Destroy()
{
	vbo.Reset();
	ibo.Reset();
	rootSignature.Reset();
	pipelineState.Reset();
}
<|endoftext|>