text:
//          Copyright Oliver Kowalke 2009.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <sstream>
#include <string>

#include <boost/test/unit_test.hpp>
#include <boost/utility.hpp>

#include <boost/fiber.hpp>

int value1 = 0;
int value2 = 0;
int value3 = 0;

void fn_1()
{
	for ( int i = 0; i < 3; ++i)
	{
		++value1;
		boost::this_fiber::yield();
		if ( i == 1)
			boost::this_fiber::cancel();
	}
}

void fn_2()
{
	for ( int i = 0; i < 3; ++i)
	{
		++value2;
		boost::this_fiber::yield();
	}
}

void fn_3( boost::fiber f)
{
	for ( int i = 0; i < 3; ++i)
	{
		++value3;
		if ( i == 1) f.cancel();
		boost::this_fiber::yield();
	}
}

void test_case_1()
{
	value1 = 0;
	value2 = 0;

	boost::fibers::scheduler<> sched;

	sched.make_fiber( fn_1, boost::fiber::default_stacksize);
	sched.make_fiber( fn_2, boost::fiber::default_stacksize);

	BOOST_CHECK_EQUAL( 0, value1);
	BOOST_CHECK_EQUAL( 0, value2);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( ! sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
	BOOST_CHECK_EQUAL( 1, value1);
	BOOST_CHECK_EQUAL( 0, value2);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( ! sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
	BOOST_CHECK_EQUAL( 1, value1);
	BOOST_CHECK_EQUAL( 1, value2);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( ! sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
	BOOST_CHECK_EQUAL( 2, value1);
	BOOST_CHECK_EQUAL( 1, value2);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( ! sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
	BOOST_CHECK_EQUAL( 2, value1);
	BOOST_CHECK_EQUAL( 2, value2);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( ! sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
	BOOST_CHECK_EQUAL( 2, value1);
	BOOST_CHECK_EQUAL( 2, value2);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( ! sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
	BOOST_CHECK_EQUAL( 2, value1);
	BOOST_CHECK_EQUAL( 3, value2);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 0), sched.size() );
	BOOST_CHECK_EQUAL( 2, value1);
	BOOST_CHECK_EQUAL( 3, value2);

	BOOST_CHECK( ! sched.run() );
	BOOST_CHECK( sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 0), sched.size() );
	BOOST_CHECK_EQUAL( 2, value1);
	BOOST_CHECK_EQUAL( 3, value2);
}

void test_case_2()
{
	value2 = 0;
	value3 = 0;

	boost::fibers::scheduler<> sched;

	boost::fiber f( fn_2, boost::fiber::default_stacksize);
	sched.submit_fiber( f);
	sched.make_fiber( fn_3, f, boost::fiber::default_stacksize);

	BOOST_CHECK_EQUAL( 0, value2);
	BOOST_CHECK_EQUAL( 0, value3);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( ! sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
	BOOST_CHECK_EQUAL( 1, value2);
	BOOST_CHECK_EQUAL( 0, value3);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( ! sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
	BOOST_CHECK_EQUAL( 1, value2);
	BOOST_CHECK_EQUAL( 1, value3);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( ! sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 2), sched.size() );
	BOOST_CHECK_EQUAL( 2, value2);
	BOOST_CHECK_EQUAL( 1, value3);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( ! sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
	BOOST_CHECK_EQUAL( 2, value2);
	BOOST_CHECK_EQUAL( 2, value3);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( ! sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 1), sched.size() );
	BOOST_CHECK_EQUAL( 2, value2);
	BOOST_CHECK_EQUAL( 3, value3);

	BOOST_CHECK( sched.run() );
	BOOST_CHECK( sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 0), sched.size() );
	BOOST_CHECK_EQUAL( 2, value2);
	BOOST_CHECK_EQUAL( 3, value3);

	BOOST_CHECK( ! sched.run() );
	BOOST_CHECK( sched.empty() );
	BOOST_CHECK_EQUAL( std::size_t( 0), sched.size() );
	BOOST_CHECK_EQUAL( 2, value2);
	BOOST_CHECK_EQUAL( 3, value3);
}

boost::unit_test::test_suite * init_unit_test_suite( int, char* [])
{
	boost::unit_test::test_suite * test =
		BOOST_TEST_SUITE("Boost.Fiber: cancel test suite");

	test->add( BOOST_TEST_CASE( & test_case_1) );
	test->add( BOOST_TEST_CASE( & test_case_2) );

	return test;
}

max_stars_repo_name: ghisguth/tasks

max_issues_repo_name: ghisguth/tasks

max_forks_repo_name: ghisguth/tasks


text:
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <queue>
#include <boost/thread/executors/basic_thread_pool.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <google/protobuf/io/coded_stream.h>
#include "message.pb.h"

/*******************************************************************
 * Configuration****************************************************
********************************************************************/
static std::string const CHAT_SERVER_AUTOR = "Chat server";
#ifdef DEBUG
static size_t const INITIAL_BUFFER_SIZE = 1 << 2; // 4 b
#else
static size_t const INITIAL_BUFFER_SIZE = 1 << 12; // 4 Kb
#endif
static size_t const MESSAGES_IN_QUEUE_TO_FALLBACK = 1 << 8; // 256
static size_t const MESSAGES_SUM_SIZE_TO_FALLBACK = 1 << 12; // 4 Kb
static size_t const MAX_VARINT_BYTES = 10;
/*******************************************************************/

using namespace boost::asio;
using ru::spbau::chat::commons::protocol::Message;
using google::protobuf::io::CodedInputStream;
using google::protobuf::io::CodedOutputStream;
using google::protobuf::uint8;
using google::protobuf::uint32;

typedef std::pair<size_t, std::shared_ptr<uint8>> serialized_message;

class chat_user
{
public:
    virtual void accept_message_size() = 0;
    virtual bool deliver_message(serialized_message const &message) = 0;
};
typedef std::shared_ptr<chat_user> user_ptr;

serialized_message serialize_message(Message const &message)
{
    size_t msg_size = message.ByteSize();
    size_t size = msg_size + MAX_VARINT_BYTES;
    std::shared_ptr<uint8> buffer(new uint8[size]);
    auto it = CodedOutputStream::WriteVarint32ToArray(msg_size, buffer.get());
    bool written = message.SerializeToArray(it, msg_size);
    assert(written);
    return serialized_message(msg_size + (it - buffer.get()), buffer);
}

class chat_room
{
public:
    chat_room()
        :
          command_executor(1)
    {
    }

    void add_new_user(user_ptr user)
    {
        rw_mutex.lock();
        users.push_back(user);
        rw_mutex.unlock();
#ifdef DEBUG
        std::cout << "User connected" << std::endl;
#endif
        user->accept_message_size();
    }

    void on_user_leave(user_ptr user)
    {
        rw_mutex.lock();
        auto pos = std::find_if(users.begin(), users.end(), [user](user_ptr &ptr)
        {
            return ptr.get() == user.get();
        });
        if (pos != users.end())
        {
            users.erase(pos);
        }
        rw_mutex.unlock();
#ifdef DEBUG
        std::cout << "User leaved" << std::endl;
#endif
    }

    size_t deliver_message_to_all(Message const &message, chat_user const *from_user)
    {
        serialized_message message_serialized(serialize_message(message));
        size_t overflow_queues = 0;
        rw_mutex.lock_shared();
        for(auto &user_p: users)
        {
            if (user_p.get() == from_user)
            {
                continue;
            }
            overflow_queues += user_p->deliver_message(message_serialized);
        }
        rw_mutex.unlock_shared();
        return overflow_queues;
    }

    void execute_command(std::string cmd, user_ptr user_to_send_result)
    {
        command_executor.submit([user_to_send_result, cmd]()
        {
            Message result;
            result.set_type(Message::MESSAGE);
            result.set_author(CHAT_SERVER_AUTOR);

            std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
            char buffer[128];
            std::string result_str;
            if (pipe)
            {
                while (!feof(pipe.get())) {
                    if (fgets(buffer, 128, pipe.get()) == NULL)
                    {
                        break;
                    }
                    result_str += buffer;
                    if (result_str.back() == '\n')
                    {
                        result_str.pop_back();
                        result.add_text(std::move(result_str));
                        result_str.clear();
                    }
                }
                if (result_str.size())
                {
                    result.add_text(result_str);
                }
            } else {
                result.add_text("Command '" + cmd + "'' execution failed!");
            }

            user_to_send_result->deliver_message(serialize_message(result));
        });
    }

private:
    std::vector<user_ptr> users;
    boost::shared_mutex rw_mutex;
    boost::executors::basic_thread_pool command_executor;
};

class user :
        public chat_user,
        public std::enable_shared_from_this<user>
{
public:
    user(ip::tcp::socket sock, chat_room &chat, io_service &service)
        :
            socket(std::move(sock)),
            chat(chat),
            service(service),
            message_buffer(std::max(INITIAL_BUFFER_SIZE, MAX_VARINT_BYTES)),
            buffer_offset(0),
            buffer_red(0),
            write_buffer(std::max(INITIAL_BUFFER_SIZE, MAX_VARINT_BYTES)),
            messages_sum_size(0),
            write_in_progress(false)
    {
    }

    void accept_message_size()
    {
        check_enougth_space(MAX_VARINT_BYTES);

        if (buffer_red)
        {
            bool read_succ;
            size_t read_bytes_count;
            uint32 message_size;
            {
                CodedInputStream input(message_buffer.data() + buffer_offset, buffer_red);
                read_succ = input.ReadVarint32(&message_size);
                read_bytes_count = input.CurrentPosition();
            }
            if (read_succ)
            {
                buffer_offset += read_bytes_count;
                buffer_red -= read_bytes_count;
                accept_message(message_size);
                return;
            }
            if (buffer_red > MAX_VARINT_BYTES)
            {
#ifdef DEBUG
                std::cout << "invalid varint: " << std::endl;
#endif
                chat.on_user_leave(shared_from_this());
                return;
            }
        }

        auto ancor(shared_from_this());
        async_read(socket, buffer(message_buffer.data() + buffer_offset + buffer_red,
                                  message_buffer.size() - buffer_offset - buffer_red),
            transfer_at_least(1),
            [this, ancor](boost::system::error_code ec, std::size_t bytes_red)
            {
#ifdef DEBUG
                std::cout << "Reading message size: bytes red "
                          << buffer_red + bytes_red << std::endl;
#endif
                if (ec)
                {
#ifdef DEBUG
                    std::cout << "error on reading message_size: " << ec.message() << std::endl;
#endif
                    chat.on_user_leave(shared_from_this());
                    return;
                } else {
                    buffer_red += bytes_red;
                    accept_message_size();
                }
            });
    }

    void accept_message(uint32 message_size)
    {
        check_enougth_space(message_size);

        if (buffer_red >= message_size)
        {
            Message message;
            try
            {
                message.ParseFromArray(message_buffer.data() + buffer_offset,
                                       message_size);
            } catch (std::exception &) {
    #ifdef DEBUG
                std::cout << "Failed to parse protobuf message" << std::endl;
    #endif
                chat.on_user_leave(shared_from_this());
                return;
            }
            buffer_offset += message_size;
            buffer_red -= message_size;

#ifdef DEBUG
            std::cout << "message red ["
                      << (message.has_type() ? message.type() : -1) << ", "
                      << (message.has_author() ? message.author() : "no author") << ", "
                      << (message.text_size() ? message.text(0) : "no text")
                      << "]" << std::endl;
#endif
            if (message.type() == Message::COMMAND)
            {
                chat.execute_command(message.text(0), shared_from_this());
            } else {
                size_t busy_factor = chat.deliver_message_to_all(message, this);
                for (size_t idx = 0; idx < busy_factor; ++idx)
                {
                    if (!service.poll_one())
                    {
                        break;
                    }
                }
            }
            accept_message_size();
            return;
        }

        auto ancor(shared_from_this());
        async_read(socket, buffer(message_buffer.data() + buffer_offset + buffer_red,
                                  message_buffer.size() - buffer_offset - buffer_red),
            transfer_at_least(message_size - buffer_red),
            [this, ancor, message_size](boost::system::error_code ec, std::size_t bytes_red)
            {
#ifdef DEBUG
                std::cout << "Reading message: bytes red "
                          << buffer_red + bytes_red << " from "
                          << message_size << std::endl;
#endif
                if (ec)
                {
#ifdef DEBUG
                    std::cout << "error: " << ec.message() << std::endl;
#endif
                    chat.on_user_leave(shared_from_this());
                    return;
                } else {
                    buffer_red += bytes_red;
                    accept_message(message_size);
                }
            });
    }

    bool deliver_message(serialized_message const &message)
    {
        boost::lock_guard<boost::mutex> guard(deliver_queue_mutex);
        messages_to_deliver.push(message);
        if (!write_in_progress)
        {
            write_in_progress = true;
            auto ancor(shared_from_this());
            service.post([this, ancor](){do_write();});
        }
        messages_sum_size += message.first;
        return messages_to_deliver.size() >= MESSAGES_IN_QUEUE_TO_FALLBACK ||
               messages_sum_size >= MESSAGES_SUM_SIZE_TO_FALLBACK;
    }

    ~user()
    {
#ifdef DEBUG
        std::cout << "user destroyed" << std::endl;
#endif
    }

private:
    void check_enougth_space(size_t space_needed)
    {
        assert(buffer_offset + buffer_red <= message_buffer.size());
        if (!buffer_red)
        {
            buffer_offset = 0;
        }
        if (buffer_offset + space_needed <= message_buffer.size())
        {
            return;
        }
        memmove(message_buffer.data(), message_buffer.data() + buffer_offset, buffer_red);
        buffer_offset = 0;
        if (space_needed > message_buffer.size())
        {
            message_buffer.resize(space_needed);
        }
    }

    void do_write()
    {
        boost::lock_guard<boost::mutex> guard(deliver_queue_mutex);
        size_t min_size = messages_to_deliver.front().first;
        if (write_buffer.size() < min_size)
        {
            write_buffer.resize(min_size);
        }
        size_t write_buffer_offset = 0;
        while (!messages_to_deliver.empty())
        {
            serialized_message const &message = messages_to_deliver.front();
            if (message.first > write_buffer.size() - write_buffer_offset)
            {
                break;
            }
#ifdef DEBUG
            std::cout << "message written" << std::endl;
#endif
            memcpy(write_buffer.data() + write_buffer_offset, message.second.get(), message.first);
            write_buffer_offset += message.first;
            messages_sum_size -= message.first;
            messages_to_deliver.pop();
        }

        auto ancor(shared_from_this());
        async_write(socket, buffer(write_buffer.data(), write_buffer_offset),
                    [this, ancor](boost::system::error_code ec, std::size_t)
        {
            if (ec)
            {
#ifdef DEBUG
                std::cout << "error writing: " << ec.message() << std::endl;
#endif
                chat.on_user_leave(shared_from_this());
                return;
            } else {
                {
                    boost::lock_guard<boost::mutex> guard(deliver_queue_mutex);
                    if (messages_to_deliver.empty())
                    {
                        write_in_progress = false;
                        return;
                    }
                }
                do_write();
            }
        });

    }

private:
    ip::tcp::socket socket;
    chat_room &chat;
    io_service &service;
    std::vector<uint8> message_buffer;
    size_t buffer_offset;
    size_t buffer_red;
    std::vector<uint8> write_buffer;
    std::queue<serialized_message> messages_to_deliver;
    boost::mutex deliver_queue_mutex;
    size_t messages_sum_size;
    bool write_in_progress;
};

class connection_handler
{
public:
    connection_handler(io_service &service, int port, chat_room &chat)
        :
          sock(service),
          service(service),
          acc(service, ip::tcp::endpoint(ip::tcp::v4(), port)),
          chat(chat)
    {
    }

public:
    void accept_new_connection()
    {
        acc.async_accept(sock, [this](boost::system::error_code)
        {
            if (sock.is_open())
            {
                sock.set_option(ip::tcp::no_delay(true));
                chat.add_new_user(std::make_shared<user>(std::move(sock), chat, service));
            }
            accept_new_connection();
        });
    }

private:
    ip::tcp::socket sock;
    io_service &service;
    ip::tcp::acceptor acc;
    chat_room &chat;
};

int main(int argc, char *argv[])
{
    if (argc < 3) {
        std::cout
                << "Usage: ./chat_server $PORT_NUMBER$ $CONCURRENCY_LEVEL$"
                << std::endl
                << "Where $CONCURRENCY_LEVEL$ - number of the worker threads"
                << std::endl;
        return -1;
    }
    size_t port = std::atoi(argv[1]);
    size_t concurrency_level = std::atoi(argv[2]);

    try
    {
        std::cout << "Starting chat server on port "
                  << port
                  << " with concurrency level "
                  << concurrency_level
                  << " ..."
                  << std::endl;

        io_service service(concurrency_level);
        chat_room chat;

        connection_handler handler(service, port, chat);
        handler.accept_new_connection();

        boost::thread_group workers;
        auto const worker =
                boost::bind(&io_service::run, &service);
        for (size_t idx = 0; idx < concurrency_level; ++idx)
        {
            workers.create_thread(worker);
        }

        std::cout << "The server is started" << std::endl;
        std::cout << "Press 'enter' to stop the server"
                  << std::endl;
        std::cin.get();
        std::cout << "Stopping the server..." << std::endl;
        service.stop();
        workers.join_all();
        std::cout << "The server is stopped" << std::endl;
    } catch(std::exception &e) {
        std::cerr << "An exception occured with ";
        if (e.what()) {
            std::cerr << "message: \"" << e.what() << '"';
        } else {
            std::cerr << "no message";
        }
        std::cerr << std::endl;
        google::protobuf::ShutdownProtobufLibrary();
        return -1;
    }

    google::protobuf::ShutdownProtobufLibrary();
    return 0;
}

ext: cpp

max_stars_repo_name: SergeyKrivohatskiy/chat-with-asio

max_issues_repo_name: SergeyKrivohatskiy/chat-with-asio

max_forks_repo_name: SergeyKrivohatskiy/chat-with-asio


text:
/* ---------------------------------------------------------------------
 *
 * Copyright (C) 1999 - 2020 by the deal.II authors
 *
 * This file is part of the deal.II library.
 *
 * The deal.II library is free software; you can use it, 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.
 * The full text of the license can be found in the file LICENSE.md at
 * the top level directory of deal.II.
 *
 * ---------------------------------------------------------------------
 *
 * Author: Wolfgang Bangerth, University of Heidelberg, 1999
 */
#include <deal.II/base/function.h>
#include <deal.II/base/logstream.h>
#include <deal.II/base/quadrature_lib.h>

#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_tools.h>

#include <deal.II/fe/fe_q.h>
#include <deal.II/fe/fe_values.h>

#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/tria.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>

#include <deal.II/lac/dynamic_sparsity_pattern.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/precondition.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/sparse_matrix.h>
#include <deal.II/lac/vector.h>

#include <deal.II/numerics/data_out.h>
#include <deal.II/numerics/matrix_tools.h>
#include <deal.II/numerics/vector_tools.h>

#include <fstream>
#include <iostream>

using namespace dealii;

template <int dim>
class Step4
{
public:
  Step4();
  void
  run();

private:
  void
  make_grid();
  void
  setup_system();
  void
  assemble_system();
  void
  solve();
  void
                       output_results() const;
  Triangulation<dim>   triangulation;
  FE_Q<dim>            fe;
  DoFHandler<dim>      dof_handler;
  SparsityPattern      sparsity_pattern;
  SparseMatrix<double> system_matrix;
  Vector<double>       solution;
  Vector<double>       system_rhs;
};
template <int dim>
class RightHandSide : public Function<dim>
{
public:
  virtual double
  value(const Point<dim> &p, const unsigned int component = 0) const override;
};
template <int dim>
class BoundaryValues : public Function<dim>
{
public:
  virtual double
  value(const Point<dim> &p, const unsigned int component = 0) const override;
};
template <int dim>
double
RightHandSide<dim>::value(const Point<dim> &p,
                          const unsigned int /*component*/) const
{
  double return_value = 0.0;
  for (unsigned int i = 0; i < dim; ++i)
    return_value += 4.0 * std::pow(p(i), 4.0);
  return return_value;
}
template <int dim>
double
BoundaryValues<dim>::value(const Point<dim> &p,
                           const unsigned int /*component*/) const
{
  return p.square();
}
template <int dim>
Step4<dim>::Step4()
  : fe(1)
  , dof_handler(triangulation)
{}
template <int dim>
void
Step4<dim>::make_grid()
{
  GridGenerator::hyper_cube(triangulation, -1, 1);
  triangulation.refine_global(4);
  std::cout << "   Number of active cells: " << triangulation.n_active_cells()
            << std::endl
            << "   Total number of cells: " << triangulation.n_cells()
            << std::endl;
}
template <int dim>
void
Step4<dim>::setup_system()
{
  dof_handler.distribute_dofs(fe);
  std::cout << "   Number of degrees of freedom: " << dof_handler.n_dofs()
            << std::endl;
  DynamicSparsityPattern dsp(dof_handler.n_dofs());
  DoFTools::make_sparsity_pattern(dof_handler, dsp);
  sparsity_pattern.copy_from(dsp);
  system_matrix.reinit(sparsity_pattern);
  solution.reinit(dof_handler.n_dofs());
  system_rhs.reinit(dof_handler.n_dofs());
}
template <int dim>
void
Step4<dim>::assemble_system()
{
  QGauss<dim>        quadrature_formula(fe.degree + 1);
  RightHandSide<dim> right_hand_side;
  FEValues<dim>      fe_values(fe,
                          quadrature_formula,
                          update_values | update_gradients |
                            update_quadrature_points | update_JxW_values);
  const unsigned int dofs_per_cell = fe.dofs_per_cell;
  FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
  Vector<double>     cell_rhs(dofs_per_cell);
  std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
  for (const auto &cell : dof_handler.active_cell_iterators())
    {
      fe_values.reinit(cell);
      cell_matrix = 0;
      cell_rhs    = 0;
      for (const unsigned int q_index : fe_values.quadrature_point_indices())
        for (const unsigned int i : fe_values.dof_indices())
          {
            for (const unsigned int j : fe_values.dof_indices())
              cell_matrix(i, j) +=
                (fe_values.shape_grad(i, q_index) * // grad phi_i(x_q)
                 fe_values.shape_grad(j, q_index) * // grad phi_j(x_q)
                 fe_values.JxW(q_index));           // dx
            const auto x_q = fe_values.quadrature_point(q_index);
            cell_rhs(i) += (fe_values.shape_value(i, q_index) * // phi_i(x_q)
                            right_hand_side.value(x_q) *        // f(x_q)
                            fe_values.JxW(q_index));            // dx
          }
      cell->get_dof_indices(local_dof_indices);
      for (const unsigned int i : fe_values.dof_indices())
        {
          for (const unsigned int j : fe_values.dof_indices())
            system_matrix.add(local_dof_indices[i],
                              local_dof_indices[j],
                              cell_matrix(i, j));
          system_rhs(local_dof_indices[i]) += cell_rhs(i);
        }
    }
  std::map<types::global_dof_index, double> boundary_values;
  VectorTools::interpolate_boundary_values(dof_handler,
                                           0,
                                           BoundaryValues<dim>(),
                                           boundary_values);
  MatrixTools::apply_boundary_values(boundary_values,
                                     system_matrix,
                                     solution,
                                     system_rhs);
}
template <int dim>
void
Step4<dim>::solve()
{
  SolverControl            solver_control(1000, 1e-12);
  SolverCG<Vector<double>> solver(solver_control);
  solver.solve(system_matrix, solution, system_rhs, PreconditionIdentity());
  std::cout << "   " << solver_control.last_step()
            << " CG iterations needed to obtain convergence." << std::endl;
}
template <int dim>
void
Step4<dim>::output_results() const
{
  DataOut<dim> data_out;
  data_out.attach_dof_handler(dof_handler);
  data_out.add_data_vector(solution, "solution");
  data_out.build_patches();
  std::ofstream output(dim == 2 ? "solution-2d.vtk" : "solution-3d.vtk");
  data_out.write_vtk(output);
}
template <int dim>
void
Step4<dim>::run()
{
  std::cout << "Solving problem in " << dim << " space dimensions."
            << std::endl;
  make_grid();
  setup_system();
  assemble_system();
  solve();
  output_results();
}
int
main()
{
  deallog.depth_console(0);
  {
    Step4<2> laplace_problem_2d;
    laplace_problem_2d.run();
  }
  {
    Step4<3> laplace_problem_3d;
    laplace_problem_3d.run();
  }
  return 0;
}

ext: cc


text:
/*
 * Copyright (C) 2012-2015 Open Source Robotics Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/
/* Desc: A class to log data
 * Author: Nate Koenig
 * Date: 1 Jun 2010
 */

#ifndef _LOGRECORD_HH_
#define _LOGRECORD_HH_

#include <fstream>
#include <string>
#include <map>
#include <boost/thread.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/ostream_iterator.hpp>
#include <boost/filesystem.hpp>

#include "gazebo/msgs/msgs.hh"
#include "gazebo/transport/TransportTypes.hh"
#include "gazebo/common/UpdateInfo.hh"
#include "gazebo/common/Event.hh"
#include "gazebo/common/SingletonT.hh"
#include "gazebo/util/system.hh"

#define GZ_LOG_VERSION "1.0"

namespace gazebo
{
  namespace util
  {
    /// addtogroup gazebo_util
    /// \{

    /// \class LogRecord LogRecord.hh util/util.hh
    /// \brief Handles logging of data to disk
    ///
    /// The LogRecord class is a Singleton that manages data logging of any
    /// entity within a running simulation. An entity may be a World, Model,
    /// or any of their child entities. This class only writes log files,
    /// see LogPlay for playback functionality.
    ///
    /// State information for an entity may be logged through the LogRecord::Add
    /// function, and stopped through the LogRecord::Remove function. Data may
    /// be logged into a single file, or split into many separate files by
    /// specifying different filenames for the LogRecord::Add function.
    ///
    /// The LogRecord is updated at the start of each simulation step. This
    /// guarantees that all data is stored.
    ///
    /// \sa Logplay, State
    class GZ_UTIL_VISIBLE LogRecord : public SingletonT<LogRecord>
    {
      /// \brief Constructor
      private: LogRecord();

      /// \brief Destructor
      private: virtual ~LogRecord();

      /// \brief Initialize logging into a subdirectory.
      ///
      /// Init may only be called once, False will be returned if called
      /// multiple times.
      /// \param[in] _subdir Directory to record to
      /// \return True if successful.
      public: bool Init(const std::string &_subdir);

      /// \brief Add an object to a log file.
      ///
      /// Add a new object to a log. An object can be any valid named object
      /// in simulation, including the world itself. Duplicate additions are
      /// ignored. Objects can be added to the same file by
      /// specifying the same _filename.
      /// \param[in] _name Name of the object to log.
      /// \param[in] _filename Filename of the log file.
      /// \param[in] _logCallback Function used to log data for the object.
      /// Typically an object will have a log function that outputs data to
      /// the provided ofstream.
      /// \throws Exception
      public: void Add(const std::string &_name, const std::string &_filename,
                    boost::function<bool (std::ostringstream &)> _logCallback);

      /// \brief Remove an entity from a log
      ///
      /// Removes an entity from the logger. The stops data recording for
      /// the entity and all its children. For example, specifying a world
      /// will stop all data logging.
      /// \param[in] _name Name of the log
      /// \return True if the entity existed and was removed. False if the
      /// entity was not registered with the logger.
      public: bool Remove(const std::string &_name);

      /// \brief Stop the logger.
      public: void Stop();

      /// \brief Tell the recorder that an update should occur.
      public: void Notify();

      /// \brief Set whether logging should pause. A paused state means the
      /// log file is still open, but data is not written to it.
      /// \param[in] _paused True to pause data logging.
      /// \sa LogRecord::GetPaused
      public: void SetPaused(bool _paused);

      /// \brief Get whether logging is paused.
      /// \return True if logging is paused.
      /// \sa LogRecord::SetPaused
      public: bool GetPaused() const;

      /// \brief Get whether the logger is ready to start, which implies
      /// that any previous runs have finished.
      // \return True if logger is ready to start.
      public: bool IsReadyToStart() const;

      /// \brief Get whether logging is running.
      /// \return True if logging has been started.
      public: bool GetRunning() const;

      /// \brief Start the logger.
      /// \param[in] _encoding The type of encoding (txt, zlib, or bz2).
      /// \param[in] _path Path in which to store log files.
      public: bool Start(const std::string &_encoding="zlib",
                  const std::string &_path="");

      /// \brief Get the encoding used.
      /// \return Either [txt, zlib, or bz2], where txt is plain txt and bz2
      /// and zlib are compressed data with Base64 encoding.
      public: const std::string &GetEncoding() const;

      /// \brief Get the filename for a log object.
      /// \param[in] _name Name of the log object.
      /// \return Filename, empty string if not found.
      public: std::string GetFilename(const std::string &_name = "") const;

      /// \brief Get the file size for a log object.
      /// \param[in] _name Name of the log object.
      /// \return Size in bytes.
      public: unsigned int GetFileSize(const std::string &_name = "") const;

      /// \brief Set the base path.
      /// \param[in] _path Path to the new logging location.
      public: void SetBasePath(const std::string &_path);

      /// \brief Get the base path for a log recording.
      /// \return Path for log recording.
      public: std::string GetBasePath() const;

      /// \brief Get the run time in sim time.
      /// \return Run sim time.
      public: common::Time GetRunTime() const;

      /// \brief Finialize, and shutdown.
      public: void Fini();

      /// \brief Return true if an Update has not yet been completed.
      /// \return True if an Update has not yet been completed.
      public: bool GetFirstUpdate() const;

      /// \brief Write all logs.
      /// \param[in] _force True to skip waiting on dataAvailableCondition.
      public: void Write(bool _force = false);

      /// \brief Get the size of the buffer.
      /// \return Size of the buffer, in bytes.
      public: unsigned int GetBufferSize() const;

      /// \brief Update the log files
      ///
      /// Captures the current state of all registered entities, and outputs
      /// the data to their respective log files.
      // private: void Update(const common::UpdateInfo &_info);
      private: void Update();

      /// \brief Function used by the update thread.
      private: void RunUpdate();

      /// \brief Run the Write loop.
      private: void RunWrite();

      /// \brief Clear and delete the log buffers.
      private: void ClearLogs();

      /// \brief Publish log status message.
      private: void PublishLogStatus();

      /// \brief Called when a log control message is received.
      /// \param[in] _data The log control message.
      private: void OnLogControl(ConstLogControlPtr &_data);

      /// \brief Cleanup log recording. A thread uses this function, you
      /// should never call this function directly. Use the Stop() function
      /// to trigger a cleanup.
      private: void Cleanup();

      /// \brief Used to get the simulation pause state.
      private: void OnPause(bool _pause);

      /// \cond
      private: class Log
      {
        /// \brief Constructor
        /// \param[in] _parent Pointer to the LogRecord parent.
        /// \param[in] _relativeFilename The name of the log file to
        /// generate, sans the complete path.
        /// \param[in] _logCB Callback function, which is used to get log
        /// data.
        public: Log(LogRecord *_parent, const std::string &_relativeFilename,
                    boost::function<bool (std::ostringstream &)> _logCB);

        /// \brief Destructor
        public: virtual ~Log();

        /// \brief Start the log.
        /// \param[in] _path The complete path in which to put the log file.
        public: void Start(const boost::filesystem::path &_path);

        /// \brief Stop logging.
        public: void Stop();

        /// \brief Write data to disk.
        public: void Write();

        /// \brief Update the data buffer.
        /// \return The size of the data buffer.
        public: unsigned int Update();

        /// \brief Clear the data buffer.
        public: void ClearBuffer();

        /// \brief Get the byte size of the buffer.
        /// \return Buffer byte size.
        public: unsigned int GetBufferSize();

        /// \brief Get the relative filename. This is the filename passed
        /// to the constructor.
        /// \return The relative filename.
        public: std::string GetRelativeFilename() const;

        /// \brief Get the complete filename.
        /// \return The complete filename.
        public: std::string GetCompleteFilename() const;

        /// \brief Pointer to the log record parent.
        public: LogRecord *parent;

        /// \brief Callback from which to get data.
        public: boost::function<bool (std::ostringstream &)> logCB;

        /// \brief Data buffer.
        public: std::string buffer;

        /// \brief The log file.
        public: std::ofstream logFile;

        /// \brief Relative log filename.
        public: std::string relativeFilename;

        /// \brief Complete file path.
        private: boost::filesystem::path completePath;
      };
      /// \endcond

      /// \def Log_M
      /// \brief Map of names to logs.
      private: typedef std::map<std::string, Log*> Log_M;

      /// \brief All the log objects.
      private: Log_M logs;

      /// \brief Iterator used to update the log objects.
      private: Log_M::iterator updateIter;

      /// \brief Convenience iterator to the end of the log objects map.
      private: Log_M::iterator logsEnd;

      /// \brief Condition used to start threads
      private: boost::condition_variable startThreadCondition;

      /// \brief Condition used to trigger an update
      private: boost::condition_variable updateCondition;

      /// \brief Used by the cleanupThread to wait for a cleanup signal.
      private: boost::condition_variable cleanupCondition;

      /// \brief True if logging is running.
      private: bool running;

      /// \brief Thread used to write data to disk.
      private: boost::thread *writeThread;

      /// \brief Thread used to update data.
      private: boost::thread *updateThread;

      /// \brief Thread to cleanup log recording.
      private: boost::thread cleanupThread;

      /// \brief Mutex to protect against parallel calls to Write()
      private: mutable boost::mutex writeMutex;

      /// \brief Mutex to synchronize with RunWrite()
      private: mutable boost::mutex runWriteMutex;

      /// \brief Mutex to synchronize with RunUpdate()
      private: mutable boost::mutex updateMutex;

      /// \brief Mutex to protect logging control.
      private: boost::mutex controlMutex;

      /// \brief Used by the write thread to know when data needs to be
      /// written to disk
      private: boost::condition_variable dataAvailableCondition;

      /// \brief The base pathname for all the logs.
      private: boost::filesystem::path logBasePath;

      /// \brief The complete pathname for all the logs.
      private: boost::filesystem::path logCompletePath;

      /// \brief Subdirectory for log files. This is appended to
      /// logBasePath.
      private: std::string logSubDir;

      /// \brief Encoding format for each chunk.
      private: std::string encoding;

      /// \brief True if initialized.
      private: bool initialized;

      /// \brief True to pause recording.
      private: bool paused;

      /// \brief Used to indicate the first update callback.
      private: bool firstUpdate;

      /// \brief Flag used to stop the write thread.
      private: bool stopThread;

      /// \brief Start simulation time.
      private: common::Time startTime;

      /// \brief Current simulation time.
      private: common::Time currTime;

      /// \brief Transportation node.
      private: transport::NodePtr node;

      /// \brief Subscriber to log control messages.
      private: transport::SubscriberPtr logControlSub;

      /// \brief Publisher of log status messages.
      private: transport::PublisherPtr logStatusPub;

      /// \brief All the event connections.
      private: event::Connection_V connections;

      /// \brief Simulation pause state.
      private: bool pauseState;

      /// \brief This is a singleton
      private: friend class SingletonT<LogRecord>;

      /// \brief True if the logger is ready to start, and the previous run
      /// has finished.
      private: bool readyToStart;
    };
    /// \}
  }
}
#endif

ext: hh

max_stars_repo_name: horikawahorikawa/gazebo-PR

max_issues_repo_name: horikawahorikawa/gazebo-PR

max_forks_repo_name: horikawahorikawa/gazebo-PR