<commit_before>#include <iostream>
#include <vector>
#include <cstring>

#include <csimsbw.h>

#include "csim/model.h"
#include "csim/executable_functions.h"
#include "csim/error_codes.h"
#include "xmlutils.h"

#define CSIM_SUCCESS 0
#define CSIM_FAILED 1

// assuming we only deal with one model at a time
class CsimWrapper {
public:
    CsimWrapper() : model(NULL) {}
    ~CsimWrapper() {
        if (model) delete model;
    }

    csim::Model* model;
};

static CsimWrapper* _csim = NULL;

int csim_loadCellml(const char* modelString)
{
    if (_csim) delete _csim;
    _csim = new CsimWrapper();
    _csim->model = new csim::Model();
    return _csim->model->loadCellmlModelFromString(modelString);
}

int csim_reset()
{
    return CSIM_SUCCESS;
}

int csim_setValue(const char* variableId, double value)
{
    return CSIM_SUCCESS;
}

int csim_getVariables(char** *outArray, int *outLength)
{
    return CSIM_SUCCESS;
}

int csim_getValues(double* *outArray, int *outLength)
{
    return CSIM_SUCCESS;
}

int csim_steadyState()
{
    return CSIM_SUCCESS;
}

int csim_simulate(
        double initialTime, double startTime, double endTime, int numSteps,
        double** *outMatrix, int* outRows, int *outCols)
{
    return CSIM_SUCCESS;
}

int csim_oneStep(double step)
{
    return CSIM_SUCCESS;
}

int csim_setTolerances(double aTol, double rTol, int maxSteps)
{
    return CSIM_SUCCESS;
}

int csim_sayHello(char* *outString, int *outLength)
{
    *outLength = 11;
    *outString = strdup("Hello World");
    return CSIM_SUCCESS;
}

int csim_serialiseCellmlFromUrl(const char* url,
                                char* *outString, int *outLength)
{
    XmlDoc xml;
    int code = xml.parseDocument(url);
    if (code != 0)
    {
        std::cerr << "Error parsing document at the URL: " << url << std::endl;
        return CSIM_FAILED;
    }
    xml.setXmlBase(url);
    std::string model = xml.dumpString();
    *outLength = model.length();
    *outString = strdup(model.c_str());
    return CSIM_SUCCESS;
}

//! Frees a vector previously allocated by this library.
void csim_freeVector(void* vector)
{
    if (vector) free(vector);
}

//! Frees a matrix previously allocated by this library.
void csim_freeMatrix(void** matrix, int numRows)
{

}
<commit_msg>instantiate the model once it loads successfully<commit_after>#include <iostream>
#include <vector>
#include <cstring>

#include <csimsbw.h>

#include "csim/model.h"
#include "csim/executable_functions.h"
#include "csim/error_codes.h"
#include "xmlutils.h"

#define CSIM_SUCCESS 0
#define CSIM_FAILED 1

// assuming we only deal with one model at a time
class CsimWrapper {
public:
    CsimWrapper() : model(NULL) {}
    ~CsimWrapper() {
        if (model) delete model;
    }

    csim::Model* model;
};

static CsimWrapper* _csim = NULL;

int csim_loadCellml(const char* modelString)
{
    if (_csim) delete _csim;
    _csim = new CsimWrapper();
    _csim->model = new csim::Model();
    int code = _csim->model->loadCellmlModelFromString(modelString);
    if (code != csim::CSIM_OK)
    {
        std::cerr << "Error loading the model from a string" << std::endl;
        return CSIM_FAILED;
    }
    code = _csim->model->instantiate();
    if (code != csim::CSIM_OK)
    {
        std::cerr << "Error instantiating model" << std::endl;
        return CSIM_FAILED;
    }
    return CSIM_SUCCESS;
}

int csim_reset()
{
    return CSIM_SUCCESS;
}

int csim_setValue(const char* variableId, double value)
{
    return CSIM_SUCCESS;
}

int csim_getVariables(char** *outArray, int *outLength)
{
    return CSIM_SUCCESS;
}

int csim_getValues(double* *outArray, int *outLength)
{
    return CSIM_SUCCESS;
}

int csim_steadyState()
{
    return CSIM_SUCCESS;
}

int csim_simulate(
        double initialTime, double startTime, double endTime, int numSteps,
        double** *outMatrix, int* outRows, int *outCols)
{
    return CSIM_SUCCESS;
}

int csim_oneStep(double step)
{
    return CSIM_SUCCESS;
}

int csim_setTolerances(double aTol, double rTol, int maxSteps)
{
    return CSIM_SUCCESS;
}

int csim_sayHello(char* *outString, int *outLength)
{
    *outLength = 11;
    *outString = strdup("Hello World");
    return CSIM_SUCCESS;
}

int csim_serialiseCellmlFromUrl(const char* url,
                                char* *outString, int *outLength)
{
    XmlDoc xml;
    int code = xml.parseDocument(url);
    if (code != 0)
    {
        std::cerr << "Error parsing document at the URL: " << url << std::endl;
        return CSIM_FAILED;
    }
    xml.setXmlBase(url);
    std::string model = xml.dumpString();
    *outLength = model.length();
    *outString = strdup(model.c_str());
    return CSIM_SUCCESS;
}

//! Frees a vector previously allocated by this library.
void csim_freeVector(void* vector)
{
    if (vector) free(vector);
}

//! Frees a matrix previously allocated by this library.
void csim_freeMatrix(void** matrix, int numRows)
{

}
<|endoftext|>


<commit_before>/*

Copyright (c) 2014 Jarryd Beck

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 <regex>
#include <set>
#include <map>
#include <exception>
#include <boost/any.hpp>
#include <sstream>

namespace cxxopts
{
  using boost::any;

  class Value
  {
    public:

    virtual void
    parse(const std::string& text) const = 0;

    virtual bool
    has_arg() const = 0;
  };

  namespace values
  {
    template <typename T>
    void
    parse_value(const std::string& text, T& value)
    {
      std::istringstream is(text);
      is >> value;
    }

    template <typename T>
    struct value_has_arg
    {
      static constexpr bool value = true;
    };

    template <>
    struct value_has_arg<bool>
    {
      static constexpr bool value = false;
    };

    template <typename T>
    class default_value : public Value
    {
      public:
      default_value()
      : m_result(std::make_shared<T>())
      , m_store(m_result.get())
      {
      }

      default_value(T* t)
      : m_store(t)
      {
      }

      void
      parse(const std::string& text) const
      {
        parse_value(text, *m_store);
      }

      bool
      has_arg() const
      {
        return value_has_arg<T>::value;
      }

      const T&
      get() const
      {
        if (m_store == nullptr)
        {
          return *m_result;
        }
        else
        {
          return *m_store;
        }
      }

      private:
      std::shared_ptr<T> m_result;
      T* m_store;
    };

  }

  template <typename T>
  std::shared_ptr<Value>
  value()
  {
    return std::make_shared<values::default_value<T>>();
  }

  class OptionException : public std::exception
  {
    public:
    OptionException(const std::string& message)
    : m_message(message)
    {
    }

    virtual const char*
    what() const noexcept
    {
      return m_message.c_str();
    }

    private:
    std::string m_message;
  };

  class OptionSpecException : public OptionException
  {
    public:

    OptionSpecException(const std::string& message)
    : OptionException(message)
    {
    }
  };

  class OptionParseException : public OptionException
  {
    public:
    OptionParseException(const std::string& message)
    : OptionException(message)
    {
    }
  };

  class option_exists_error : public OptionSpecException
  {
    public:
    option_exists_error(const std::string& option)
    : OptionSpecException(u8"Option ‘" + option + u8"’ already exists")
    {
    }
  };

  class invalid_option_format_error : public OptionSpecException
  {
    public:
    invalid_option_format_error(const std::string& format)
    : OptionSpecException(u8"Invalid option format ‘" + format + u8"’")
    {
    }
  };

  class option_not_exists_exception : public OptionParseException
  {
    public:
    option_not_exists_exception(const std::string& option)
    : OptionParseException(u8"Option ‘" + option + u8"’ does not exist")
    {
    }
  };

  class missing_argument_exception : public OptionParseException
  {
    public:
    missing_argument_exception(const std::string& option)
    : OptionParseException(u8"Option ‘" + option + u8"’ is missing an argument")
    {
    }
  };

  class option_requires_argument_exception : public OptionParseException
  {
    public:
    option_requires_argument_exception(const std::string& option)
    : OptionParseException(u8"Option ‘" + option + u8"’ requires an argument")
    {
    }
  };

  class option_not_has_argument_exception : public OptionParseException
  {
    public:
    option_not_has_argument_exception
    (
      const std::string& option,
      const std::string& arg
    )
    : OptionParseException(
        u8"Option ‘" + option + u8"’ does not take an argument, but argument‘"
        + arg + "’ given")
    {
    }
  };

  class option_not_present_exception : public OptionParseException
  {
    public:
    option_not_present_exception(const std::string& option)
    : OptionParseException(u8"Option ‘" + option + u8"’ not present")
    {
    }
  };

  class OptionAdder;

  class OptionDetails
  {
    public:
    OptionDetails
    (
      const std::string& description,
      std::shared_ptr<const Value> value
    )
    : m_desc(description)
    , m_value(value)
    , m_count(0)
    {
    }

    const std::string&
    description() const
    {
      return m_desc;
    }

    bool
    has_arg() const
    {
      return m_value->has_arg();
    }

    void
    parse(const std::string& text)
    {
      m_value->parse(text);
      ++m_count;
    }

    int
    count() const
    {
      return m_count;
    }

    template <typename T>
    const T&
    as() const
    {
      return dynamic_cast<const values::default_value<T>&>(*m_value).get();
    }

    private:
    std::string m_desc;
    std::shared_ptr<const Value> m_value;
    int m_count;
  };

  class Options
  {
    public:

    void
    parse(int& argc, char**& argv);

    OptionAdder
    add_options();

    int
    count(const std::string& o) const
    {
      auto iter = m_options.find(o);
      if (iter == m_options.end())
      {
        return 0;
      }

      return iter->second->count();
    }

    const OptionDetails&
    operator[](const std::string& option) const
    {
      auto iter = m_options.find(option);

      if (iter == m_options.end())
      {
        throw option_not_present_exception(option);
      }

      return *iter->second;
    }

    private:
    friend class OptionAdder;

    void
    parse_option
    (
      std::shared_ptr<OptionDetails> value,
      const std::string& name,
      const std::string& arg = ""
    );

    void
    checked_parse_arg
    (
      int argc,
      char* argv[],
      int argPos,
      std::shared_ptr<OptionDetails> value,
      const std::string& name
    );

    std::map<std::string, std::shared_ptr<OptionDetails>> m_options;
  };

  class OptionAdder
  {
    public:

    OptionAdder(Options& options)
    : m_options(options)
    {
    }

    OptionAdder&
    operator()
    (
      const std::string& opts,
      const std::string& desc,
      std::shared_ptr<const Value> value
        = ::cxxopts::value<bool>()
    );

    private:
    Options& m_options;
  };

}
<commit_msg>remove boost dependency<commit_after>/*

Copyright (c) 2014 Jarryd Beck

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 <regex>
#include <set>
#include <map>
#include <exception>
#include <sstream>

namespace cxxopts
{
  class Value
  {
    public:

    virtual void
    parse(const std::string& text) const = 0;

    virtual bool
    has_arg() const = 0;
  };

  namespace values
  {
    template <typename T>
    void
    parse_value(const std::string& text, T& value)
    {
      std::istringstream is(text);
      is >> value;
    }

    template <typename T>
    struct value_has_arg
    {
      static constexpr bool value = true;
    };

    template <>
    struct value_has_arg<bool>
    {
      static constexpr bool value = false;
    };

    template <typename T>
    class default_value : public Value
    {
      public:
      default_value()
      : m_result(std::make_shared<T>())
      , m_store(m_result.get())
      {
      }

      default_value(T* t)
      : m_store(t)
      {
      }

      void
      parse(const std::string& text) const
      {
        parse_value(text, *m_store);
      }

      bool
      has_arg() const
      {
        return value_has_arg<T>::value;
      }

      const T&
      get() const
      {
        if (m_store == nullptr)
        {
          return *m_result;
        }
        else
        {
          return *m_store;
        }
      }

      private:
      std::shared_ptr<T> m_result;
      T* m_store;
    };

  }

  template <typename T>
  std::shared_ptr<Value>
  value()
  {
    return std::make_shared<values::default_value<T>>();
  }

  class OptionException : public std::exception
  {
    public:
    OptionException(const std::string& message)
    : m_message(message)
    {
    }

    virtual const char*
    what() const noexcept
    {
      return m_message.c_str();
    }

    private:
    std::string m_message;
  };

  class OptionSpecException : public OptionException
  {
    public:

    OptionSpecException(const std::string& message)
    : OptionException(message)
    {
    }
  };

  class OptionParseException : public OptionException
  {
    public:
    OptionParseException(const std::string& message)
    : OptionException(message)
    {
    }
  };

  class option_exists_error : public OptionSpecException
  {
    public:
    option_exists_error(const std::string& option)
    : OptionSpecException(u8"Option ‘" + option + u8"’ already exists")
    {
    }
  };

  class invalid_option_format_error : public OptionSpecException
  {
    public:
    invalid_option_format_error(const std::string& format)
    : OptionSpecException(u8"Invalid option format ‘" + format + u8"’")
    {
    }
  };

  class option_not_exists_exception : public OptionParseException
  {
    public:
    option_not_exists_exception(const std::string& option)
    : OptionParseException(u8"Option ‘" + option + u8"’ does not exist")
    {
    }
  };

  class missing_argument_exception : public OptionParseException
  {
    public:
    missing_argument_exception(const std::string& option)
    : OptionParseException(u8"Option ‘" + option + u8"’ is missing an argument")
    {
    }
  };

  class option_requires_argument_exception : public OptionParseException
  {
    public:
    option_requires_argument_exception(const std::string& option)
    : OptionParseException(u8"Option ‘" + option + u8"’ requires an argument")
    {
    }
  };

  class option_not_has_argument_exception : public OptionParseException
  {
    public:
    option_not_has_argument_exception
    (
      const std::string& option,
      const std::string& arg
    )
    : OptionParseException(
        u8"Option ‘" + option + u8"’ does not take an argument, but argument‘"
        + arg + "’ given")
    {
    }
  };

  class option_not_present_exception : public OptionParseException
  {
    public:
    option_not_present_exception(const std::string& option)
    : OptionParseException(u8"Option ‘" + option + u8"’ not present")
    {
    }
  };

  class OptionAdder;

  class OptionDetails
  {
    public:
    OptionDetails
    (
      const std::string& description,
      std::shared_ptr<const Value> value
    )
    : m_desc(description)
    , m_value(value)
    , m_count(0)
    {
    }

    const std::string&
    description() const
    {
      return m_desc;
    }

    bool
    has_arg() const
    {
      return m_value->has_arg();
    }

    void
    parse(const std::string& text)
    {
      m_value->parse(text);
      ++m_count;
    }

    int
    count() const
    {
      return m_count;
    }

    template <typename T>
    const T&
    as() const
    {
      return dynamic_cast<const values::default_value<T>&>(*m_value).get();
    }

    private:
    std::string m_desc;
    std::shared_ptr<const Value> m_value;
    int m_count;
  };

  class Options
  {
    public:

    void
    parse(int& argc, char**& argv);

    OptionAdder
    add_options();

    int
    count(const std::string& o) const
    {
      auto iter = m_options.find(o);
      if (iter == m_options.end())
      {
        return 0;
      }

      return iter->second->count();
    }

    const OptionDetails&
    operator[](const std::string& option) const
    {
      auto iter = m_options.find(option);

      if (iter == m_options.end())
      {
        throw option_not_present_exception(option);
      }

      return *iter->second;
    }

    private:
    friend class OptionAdder;

    void
    parse_option
    (
      std::shared_ptr<OptionDetails> value,
      const std::string& name,
      const std::string& arg = ""
    );

    void
    checked_parse_arg
    (
      int argc,
      char* argv[],
      int argPos,
      std::shared_ptr<OptionDetails> value,
      const std::string& name
    );

    std::map<std::string, std::shared_ptr<OptionDetails>> m_options;
  };

  class OptionAdder
  {
    public:

    OptionAdder(Options& options)
    : m_options(options)
    {
    }

    OptionAdder&
    operator()
    (
      const std::string& opts,
      const std::string& desc,
      std::shared_ptr<const Value> value
        = ::cxxopts::value<bool>()
    );

    private:
    Options& m_options;
  };

}
<|endoftext|>


<commit_before>// $Id: libmesh.C,v 1.32 2005-05-11 23:11:58 benkirk Exp $

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

// 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 <iostream>

// Local includes
#include "libmesh.h"
#include "auto_ptr.h"
#include "getpot.h"
#include "reference_counter.h"

#if defined(HAVE_MPI)
# include <mpi.h>
# if defined(HAVE_PETSC)
#  ifndef USE_COMPLEX_NUMBERS
extern "C" {
#   include <petsc.h>
#   include <petscerror.h>
}
#  else
#   include <petsc.h>
#   include <petscerror.h>
#  endif
# endif // #if defined(HAVE_PETSC)
# if defined(HAVE_SLEPC)
#  ifndef USE_COMPLEX_NUMBERS
extern "C"
{
#   include <slepc.h>
}
#  else
#   include <slepc.h>
#  endif
# endif // #if defined(HAVE_SLEPC)
#endif // #if defined(HAVE_MPI)

// --------------------------------------------------------
// Local anonymous namespace to hold miscelaneous variables
namespace {
  AutoPtr<GetPot> command_line (NULL);
  bool libmesh_initialized_mpi = false;
}

// ------------------------------------------------------------
// libMesh data initialization
#ifdef HAVE_MPI
MPI_Comm           libMesh::COMM_WORLD = MPI_COMM_NULL;
#endif

PerfLog            libMesh::perflog ("libMesh",
#ifdef ENABLE_PERFORMANCE_LOGGING
				     true
#else
				     false
#endif
				     );

const Real         libMesh::pi = 3.1415926535897932384626433832795029L;

#ifdef USE_COMPLEX_NUMBERS
const Number       libMesh::imaginary (0., 1.);
const Number       libMesh::zero      (0., 0.);
#else
const Number       libMesh::zero = 0.;
#endif

const unsigned int libMesh::invalid_uint = static_cast<unsigned int>(-1);

// ------------------------------------------------------------
// libMesh::libMeshPrivateData data initialization
int           libMesh::libMeshPrivateData::_n_processors = 1;
int           libMesh::libMeshPrivateData::_processor_id = 0;
bool          libMesh::libMeshPrivateData::_is_initialized = false;
SolverPackage libMesh::libMeshPrivateData::_solver_package =
#if   defined(HAVE_PETSC)   // PETSc is the default
                                                       PETSC_SOLVERS;
#elif defined(HAVE_LASPACK) // Use LASPACK if PETSc isn't there
                                                       LASPACK_SOLVERS;
#else                       // No valid linear solver package at compile time
                                                       INVALID_SOLVER_PACKAGE;
#endif

// ------------------------------------------------------------
// libMesh functions
#ifndef HAVE_MPI
void libMesh::init (int &argc, char** & argv)
#else
void libMesh::init (int &argc, char** & argv,
		    MPI_Comm COMM_WORLD_IN)
#endif
{
  // should _not_ be initialized already.
  assert (!libMesh::initialized());

  // Build a command-line parser.
  command_line.reset(new GetPot (argc, argv));

#if defined(HAVE_MPI)

  // Allow the user to bypass PETSc initialization
  if (!libMesh::on_command_line ("--disable-mpi"))
    {
      int flag;
      MPI_Initialized (&flag);

      if (!flag)
	{
	  MPI_Init (&argc, &argv);
	  libmesh_initialized_mpi = true;
	}

      // Duplicate the input communicator for internal use
      MPI_Comm_dup (COMM_WORLD_IN, &libMesh::COMM_WORLD);
      MPI_Comm_set_name (libMesh::COMM_WORLD, "libMesh::COMM_WORLD");

      MPI_Comm_rank (libMesh::COMM_WORLD, &libMeshPrivateData::_processor_id);
      MPI_Comm_size (libMesh::COMM_WORLD, &libMeshPrivateData::_n_processors);

# if defined(HAVE_PETSC)

      if (!libMesh::on_command_line ("--disable-petsc"))
	{
	  int ierr=0;
	  ierr = PetscSetCommWorld (libMesh::COMM_WORLD);
	         CHKERRABORT(libMesh::COMM_WORLD,ierr);

#  if defined(HAVE_SLEPC)
	  ierr = SlepcInitialize  (&argc, &argv, NULL, NULL);
	         CHKERRABORT(libMesh::COMM_WORLD,ierr);
#  else
	  ierr = PetscInitialize (&argc, &argv, NULL, NULL);
	         CHKERRABORT(libMesh::COMM_WORLD,ierr);
#  endif
	}
# endif
    }
#else

  // No MPI, can only be uniprocessor
  assert (libMeshPrivateData::_n_processors == 1);
  assert (libMeshPrivateData::_processor_id == 0);

#endif

  // Could we have gotten bad values from the above calls?
  assert (libMeshPrivateData::_n_processors >  0);
  assert (libMeshPrivateData::_processor_id >= 0);

  // Re-parse the command-line arguments.  Note that PETSc and MPI
  // initialization above may have removed command line arguments
  // that are not relevant to this application in the above calls.
  // We don't want a false-positive by detecting those arguments.
  command_line->parse_command_line (argc, argv);

  // The following line is an optimization when simultaneous
  // C and C++ style access to output streams is not required.
  // The amount of benefit which occurs is probably implementation
  // defined, and may be nothing.  On the other hand, I have seen
  // some IO tests where IO peformance improves by a factor of two.
  if (!libMesh::on_command_line ("--sync-with-stdio"))
    std::ios::sync_with_stdio(false);

  // redirect std::cout to nothing on all
  // other processors unless explicitly told
  // not to via the --keep-cout command-line argument.
  if (libMesh::processor_id() != 0)
    if (!libMesh::on_command_line ("--keep-cout"))
      std::cout.rdbuf (NULL);

  // The library is now ready for use
  libMeshPrivateData::_is_initialized = true;

  // Make sure these work.  Library methods
  // depend on these being implemented properly,
  // so this is a good time to test them!
  assert (libMesh::initialized());
  assert (!libMesh::closed());
}

int libMesh::close ()
{

#if defined(HAVE_MPI)
  // Allow the user to bypass MPI finalization
  if (!libMesh::on_command_line ("--disable-mpi"))
    {
# if defined(HAVE_PETSC)

      // Allow the user to bypass PETSc finalization
      if (!libMesh::on_command_line ("--disable-petsc"))
	{
#  if defined(HAVE_SLEPC)
	  SlepcFinalize();
#  else
	  PetscFinalize();
#  endif
	}
# endif
      MPI_Comm_free (&libMesh::COMM_WORLD);

      if (libmesh_initialized_mpi)
	MPI_Finalize();
    }
#endif

  // Force the \p ReferenceCounter to print
  // its reference count information.  This allows
  // us to find memory leaks.  By default the
  // \p ReferenceCounter only prints its information
  // when the last created object has been destroyed.
  // That does no good if we are leaking memory!
  ReferenceCounter::print_info ();

  // Print an informative message if we detect a memory leak
  if (ReferenceCounter::n_objects() != 0)
    {
      std::cerr << "Memory leak detected!"
		<< std::endl;

#if !defined(ENABLE_REFERENCE_COUNTING) || defined(NDEBUG)

      std::cerr << "Compile in DEBUG mode with --enable-reference-counting"
		<< std::endl
		<< "for more information"
		<< std::endl;
#endif

    }

  // Reconnect the output streams
  // (don't do this, or we will get messages from objects
  //  that go out of scope after the following return)
  //std::cout.rdbuf(std::cerr.rdbuf());

  // Set the initialized() flag to false
  libMeshPrivateData::_is_initialized = false;

  // Return the number of outstanding objects.
  // This is equivalent to return 0 if all of
  // the reference counted objects have been
  // deleted.
  return static_cast<int>(ReferenceCounter::n_objects());
}

bool libMesh::on_command_line (const std::string& arg)
{
  // Make sure the command line parser is ready for use
  assert (command_line.get() != NULL);

  return command_line->search (arg);
}

SolverPackage libMesh::default_solver_package ()
{
  assert (libMesh::initialized());

  static bool called = false;

  // Check the command line.  Since the command line is
  // unchanging it is sufficient to do this only once.
  if (!called)
    {
      called = true;

#ifdef HAVE_PETSC
      if (libMesh::on_command_line ("--use-petsc"))
	libMeshPrivateData::_solver_package = PETSC_SOLVERS;
#endif

#ifdef HAVE_LASPACK
      if (libMesh::on_command_line ("--use-laspack"  ) ||
	  libMesh::on_command_line ("--disable-petsc"))
	libMeshPrivateData::_solver_package = LASPACK_SOLVERS;
#endif

    }

  return libMeshPrivateData::_solver_package;
}
<commit_msg>removed deprecated PetscSetCommWorld<commit_after>// $Id: libmesh.C,v 1.33 2005-05-17 15:56:45 benkirk Exp $

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

// 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 <iostream>

// Local includes
#include "libmesh.h"
#include "auto_ptr.h"
#include "getpot.h"
#include "reference_counter.h"

#if defined(HAVE_MPI)
# include <mpi.h>
# if defined(HAVE_PETSC)
#  ifndef USE_COMPLEX_NUMBERS
extern "C" {
#   include <petsc.h>
#   include <petscerror.h>
}
#  else
#   include <petsc.h>
#   include <petscerror.h>
#  endif
# endif // #if defined(HAVE_PETSC)
# if defined(HAVE_SLEPC)
#  ifndef USE_COMPLEX_NUMBERS
extern "C"
{
#   include <slepc.h>
}
#  else
#   include <slepc.h>
#  endif
# endif // #if defined(HAVE_SLEPC)
#endif // #if defined(HAVE_MPI)

// --------------------------------------------------------
// Local anonymous namespace to hold miscelaneous variables
namespace {
  AutoPtr<GetPot> command_line (NULL);
  bool libmesh_initialized_mpi = false;
}

// ------------------------------------------------------------
// libMesh data initialization
#ifdef HAVE_MPI
MPI_Comm           libMesh::COMM_WORLD = MPI_COMM_NULL;
#endif

PerfLog            libMesh::perflog ("libMesh",
#ifdef ENABLE_PERFORMANCE_LOGGING
				     true
#else
				     false
#endif
				     );

const Real         libMesh::pi = 3.1415926535897932384626433832795029L;

#ifdef USE_COMPLEX_NUMBERS
const Number       libMesh::imaginary (0., 1.);
const Number       libMesh::zero      (0., 0.);
#else
const Number       libMesh::zero = 0.;
#endif

const unsigned int libMesh::invalid_uint = static_cast<unsigned int>(-1);

// ------------------------------------------------------------
// libMesh::libMeshPrivateData data initialization
int           libMesh::libMeshPrivateData::_n_processors = 1;
int           libMesh::libMeshPrivateData::_processor_id = 0;
bool          libMesh::libMeshPrivateData::_is_initialized = false;
SolverPackage libMesh::libMeshPrivateData::_solver_package =
#if   defined(HAVE_PETSC)   // PETSc is the default
                                                       PETSC_SOLVERS;
#elif defined(HAVE_LASPACK) // Use LASPACK if PETSc isn't there
                                                       LASPACK_SOLVERS;
#else                       // No valid linear solver package at compile time
                                                       INVALID_SOLVER_PACKAGE;
#endif

// ------------------------------------------------------------
// libMesh functions
#ifndef HAVE_MPI
void libMesh::init (int &argc, char** & argv)
#else
void libMesh::init (int &argc, char** & argv,
		    MPI_Comm COMM_WORLD_IN)
#endif
{
  // should _not_ be initialized already.
  assert (!libMesh::initialized());

  // Build a command-line parser.
  command_line.reset(new GetPot (argc, argv));

#if defined(HAVE_MPI)

  // Allow the user to bypass PETSc initialization
  if (!libMesh::on_command_line ("--disable-mpi"))
    {
      int flag;
      MPI_Initialized (&flag);

      if (!flag)
	{
	  MPI_Init (&argc, &argv);
	  libmesh_initialized_mpi = true;
	}

      // Duplicate the input communicator for internal use
      MPI_Comm_dup (COMM_WORLD_IN, &libMesh::COMM_WORLD);
      MPI_Comm_set_name (libMesh::COMM_WORLD, "libMesh::COMM_WORLD");

      MPI_Comm_rank (libMesh::COMM_WORLD, &libMeshPrivateData::_processor_id);
      MPI_Comm_size (libMesh::COMM_WORLD, &libMeshPrivateData::_n_processors);

# if defined(HAVE_PETSC)

      if (!libMesh::on_command_line ("--disable-petsc"))
	{
	  PETSC_COMM_WORLD = libMesh::COMM_WORLD;

#  if defined(HAVE_SLEPC)
	  ierr = SlepcInitialize  (&argc, &argv, NULL, NULL);
	         CHKERRABORT(libMesh::COMM_WORLD,ierr);
#  else
	  ierr = PetscInitialize (&argc, &argv, NULL, NULL);
	         CHKERRABORT(libMesh::COMM_WORLD,ierr);
#  endif
	}
# endif
    }
#else

  // No MPI, can only be uniprocessor
  assert (libMeshPrivateData::_n_processors == 1);
  assert (libMeshPrivateData::_processor_id == 0);

#endif

  // Could we have gotten bad values from the above calls?
  assert (libMeshPrivateData::_n_processors >  0);
  assert (libMeshPrivateData::_processor_id >= 0);

  // Re-parse the command-line arguments.  Note that PETSc and MPI
  // initialization above may have removed command line arguments
  // that are not relevant to this application in the above calls.
  // We don't want a false-positive by detecting those arguments.
  command_line->parse_command_line (argc, argv);

  // The following line is an optimization when simultaneous
  // C and C++ style access to output streams is not required.
  // The amount of benefit which occurs is probably implementation
  // defined, and may be nothing.  On the other hand, I have seen
  // some IO tests where IO peformance improves by a factor of two.
  if (!libMesh::on_command_line ("--sync-with-stdio"))
    std::ios::sync_with_stdio(false);

  // redirect std::cout to nothing on all
  // other processors unless explicitly told
  // not to via the --keep-cout command-line argument.
  if (libMesh::processor_id() != 0)
    if (!libMesh::on_command_line ("--keep-cout"))
      std::cout.rdbuf (NULL);

  // The library is now ready for use
  libMeshPrivateData::_is_initialized = true;

  // Make sure these work.  Library methods
  // depend on these being implemented properly,
  // so this is a good time to test them!
  assert (libMesh::initialized());
  assert (!libMesh::closed());
}

int libMesh::close ()
{

#if defined(HAVE_MPI)
  // Allow the user to bypass MPI finalization
  if (!libMesh::on_command_line ("--disable-mpi"))
    {
# if defined(HAVE_PETSC)

      // Allow the user to bypass PETSc finalization
      if (!libMesh::on_command_line ("--disable-petsc"))
	{
#  if defined(HAVE_SLEPC)
	  SlepcFinalize();
#  else
	  PetscFinalize();
#  endif
	}
# endif
      MPI_Comm_free (&libMesh::COMM_WORLD);

      if (libmesh_initialized_mpi)
	MPI_Finalize();
    }
#endif

  // Force the \p ReferenceCounter to print
  // its reference count information.  This allows
  // us to find memory leaks.  By default the
  // \p ReferenceCounter only prints its information
  // when the last created object has been destroyed.
  // That does no good if we are leaking memory!
  ReferenceCounter::print_info ();

  // Print an informative message if we detect a memory leak
  if (ReferenceCounter::n_objects() != 0)
    {
      std::cerr << "Memory leak detected!"
		<< std::endl;

#if !defined(ENABLE_REFERENCE_COUNTING) || defined(NDEBUG)

      std::cerr << "Compile in DEBUG mode with --enable-reference-counting"
		<< std::endl
		<< "for more information"
		<< std::endl;
#endif

    }

  // Reconnect the output streams
  // (don't do this, or we will get messages from objects
  //  that go out of scope after the following return)
  //std::cout.rdbuf(std::cerr.rdbuf());

  // Set the initialized() flag to false
  libMeshPrivateData::_is_initialized = false;

  // Return the number of outstanding objects.
  // This is equivalent to return 0 if all of
  // the reference counted objects have been
  // deleted.
  return static_cast<int>(ReferenceCounter::n_objects());
}

bool libMesh::on_command_line (const std::string& arg)
{
  // Make sure the command line parser is ready for use
  assert (command_line.get() != NULL);

  return command_line->search (arg);
}

SolverPackage libMesh::default_solver_package ()
{
  assert (libMesh::initialized());

  static bool called = false;

  // Check the command line.  Since the command line is
  // unchanging it is sufficient to do this only once.
  if (!called)
    {
      called = true;

#ifdef HAVE_PETSC
      if (libMesh::on_command_line ("--use-petsc"))
	libMeshPrivateData::_solver_package = PETSC_SOLVERS;
#endif

#ifdef HAVE_LASPACK
      if (libMesh::on_command_line ("--use-laspack"  ) ||
	  libMesh::on_command_line ("--disable-petsc"))
	libMeshPrivateData::_solver_package = LASPACK_SOLVERS;
#endif

    }

  return libMeshPrivateData::_solver_package;
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993-2010 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "Score.h"
#include "bzfsAPI.h"
#include "WorldEventManager.h"

// bzflag library headers
#include "Pack.h"

// API headers for notification

float Score::tkKickRatio = 3.0;
int   Score::score       = 999;
bool  Score::randomRanking = false;

bool Score::KeepPlayerScores = true;
bool Score::KeepTeamScores = true;

Score::Score(): wins(0), losses(0), tks(0) {
  playerID = -1;
}

void Score::dump() {
  std::cout << wins << '-' << losses;
}

float Score::ranking() {
  if (randomRanking)
    return (float)bzfrand();

  // otherwise do score-based ranking
  int sum = wins + losses;
  if (sum == 0)
    return 0.5;
  float average = (float)wins/(float)sum;
  // IIRC that is how wide is the gaussian
  float penalty = (1.0f - 0.5f / sqrt((float)sum));
  return average * penalty;
}

bool Score::isTK() {
  // arbitrary 3
  return (tks >= 3) && (tkKickRatio > 0)
    && ((wins == 0) || (tks * 100 / wins > tkKickRatio));
}

void Score::tK() {
  if (KeepPlayerScores)
  {
    ++tks;
    worldEventManager.callEvents(bz_PlayerScoreChangeEventData_V1(playerID,bz_eTKs, tks-1, tks));
  }
}

void Score::killedBy() {
  if (KeepPlayerScores)
  {
    ++losses;
    worldEventManager.callEvents(bz_PlayerScoreChangeEventData_V1(playerID,bz_eLosses, losses-1, losses));
  }
}

void Score::kill() {
  if (KeepPlayerScores)
  {
    ++wins;
    worldEventManager.callEvents(bz_PlayerScoreChangeEventData_V1(playerID,bz_eWins, wins-1, wins));
  }
}

void *Score::pack(void *buf) {
  buf = nboPackUShort(buf, wins);
  buf = nboPackUShort(buf, losses);
  buf = nboPackUShort(buf, tks);
  return buf;
}

bool Score::reached() {
  return wins - losses >= score;
}

void Score::setTeamKillRatio(int _tkKickRatio) {
  tkKickRatio = (float)_tkKickRatio;
}

void Score::setWinLimit(int _score) {
  score = _score;
}

void Score::setRandomRanking() {
  randomRanking = true;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>ws<commit_after>/* bzflag
 * Copyright (c) 1993-2010 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "Score.h"
#include "bzfsAPI.h"
#include "WorldEventManager.h"

// bzflag library headers
#include "Pack.h"

// API headers for notification

float Score::tkKickRatio = 3.0;
int   Score::score       = 999;
bool  Score::randomRanking = false;

bool Score::KeepPlayerScores = true;
bool Score::KeepTeamScores = true;

Score::Score(): wins(0), losses(0), tks(0) {
  playerID = -1;
}

void Score::dump() {
  std::cout << wins << '-' << losses;
}

float Score::ranking() {
  if (randomRanking)
    return (float)bzfrand();

  // otherwise do score-based ranking
  int sum = wins + losses;
  if (sum == 0)
    return 0.5;
  float average = (float)wins/(float)sum;
  // IIRC that is how wide is the gaussian
  float penalty = (1.0f - 0.5f / sqrt((float)sum));
  return average * penalty;
}

bool Score::isTK() {
  // arbitrary 3
  return (tks >= 3) && (tkKickRatio > 0)
    && ((wins == 0) || (tks * 100 / wins > tkKickRatio));
}

void Score::tK() {
  if (KeepPlayerScores) {
    ++tks;
    worldEventManager.callEvents(bz_PlayerScoreChangeEventData_V1(playerID,bz_eTKs, tks-1, tks));
  }
}

void Score::killedBy() {
  if (KeepPlayerScores) {
    ++losses;
    worldEventManager.callEvents(bz_PlayerScoreChangeEventData_V1(playerID,bz_eLosses, losses-1, losses));
  }
}

void Score::kill() {
  if (KeepPlayerScores) {
    ++wins;
    worldEventManager.callEvents(bz_PlayerScoreChangeEventData_V1(playerID,bz_eWins, wins-1, wins));
  }
}

void *Score::pack(void *buf) {
  buf = nboPackUShort(buf, wins);
  buf = nboPackUShort(buf, losses);
  buf = nboPackUShort(buf, tks);
  return buf;
}

bool Score::reached() {
  return wins - losses >= score;
}

void Score::setTeamKillRatio(int _tkKickRatio) {
  tkKickRatio = (float)_tkKickRatio;
}

void Score::setWinLimit(int _score) {
  score = _score;
}

void Score::setRandomRanking() {
  randomRanking = true;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2019 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Client.hxx"
#include "Error.hxx"
#include "Parser.hxx"
#include "pool/pool.hxx"
#include "pool/LeakDetector.hxx"
#include "istream/Handler.hxx"
#include "istream/UnusedPtr.hxx"
#include "istream/Pointer.hxx"
#include "istream/istream_null.hxx"
#include "http/HeaderParser.hxx"
#include "stopwatch.hxx"
#include "strmap.hxx"
#include "HttpResponseHandler.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "util/Cast.hxx"
#include "util/Cancellable.hxx"
#include "util/DestructObserver.hxx"
#include "util/Exception.hxx"

#include <string.h>
#include <stdlib.h>

class CGIClient final : PoolLeakDetector, Istream, IstreamHandler, Cancellable, DestructAnchor {
    const StopwatchPtr stopwatch;

    IstreamPointer input;
    SliceFifoBuffer buffer;

    CGIParser parser;

    /**
     * This flag is true while cgi_parse_headers() is calling
     * HttpResponseHandler::InvokeResponse().  In this case,
     * istream_read(cgi->input) is already up in the stack, and must
     * not be called again.
     */
    bool in_response_callback;

    bool had_input, had_output;

    HttpResponseHandler &handler;

public:
    CGIClient(struct pool &_pool, StopwatchPtr &&_stopwatch,
              UnusedIstreamPtr _input,
              HttpResponseHandler &_handler,
              CancellablePointer &cancel_ptr);

    /**
     * @return false if the connection has been closed
     */
    bool ReturnResponse();

    /**
     * Feed data into the input buffer and continue parsing response
     * headers from it.  After this function returns, the response may
     * have been delivered to the response handler, and the caller should
     * post the rest of the specified buffer to the response body stream.
     *
     * Caller must hold pool reference.
     *
     * @return the number of bytes consumed from the specified buffer
     * (moved to the input buffer), 0 if the object has been closed
     */
    size_t FeedHeaders(const void *data, size_t length);

    /**
     * Call FeedHeaders() in a loop, to parse as much as possible.
     *
     * Caller must hold pool reference.
     */
    size_t FeedHeadersLoop(const char *data, size_t length);

    /**
     * Caller must hold pool reference.
     */
    size_t FeedHeadersCheck(const char *data, size_t length);

    size_t FeedBody(const char *data, size_t length);

    /* virtual methods from class Cancellable */
    void Cancel() noexcept override;

    /* virtual methods from class Istream */
    off_t _GetAvailable(bool partial) noexcept override;
    void _Read() noexcept override;
    void _Close() noexcept override;

    /* virtual methods from class IstreamHandler */
    size_t OnData(const void *data, size_t length) noexcept override;
    ssize_t OnDirect(FdType type, int fd, size_t max_length) noexcept override;
    void OnEof() noexcept override;
    void OnError(std::exception_ptr ep) noexcept override;
};

inline bool
CGIClient::ReturnResponse()
{
    http_status_t status = parser.GetStatus();
    StringMap &headers = parser.GetHeaders();

    if (http_status_is_empty(status)) {
        /* this response does not have a response body, as indicated
           by the HTTP status code */

        stopwatch.RecordEvent("empty");

        buffer.Free();
        input.ClearAndClose();
        handler.InvokeResponse(status, std::move(headers), UnusedIstreamPtr());
        Destroy();
        return false;
    } else if (parser.IsEOF()) {
        /* the response body is empty */

        stopwatch.RecordEvent("empty");

        buffer.Free();
        input.ClearAndClose();
        handler.InvokeResponse(status, std::move(headers),
                               istream_null_new(GetPool()));
        Destroy();
        return false;
    } else {
        stopwatch.RecordEvent("headers");

        const DestructObserver destructed(*this);

        in_response_callback = true;
        handler.InvokeResponse(status, std::move(headers),
                               UnusedIstreamPtr(this));
        if (destructed)
            return false;

        in_response_callback = false;
        return true;
    }
}

inline size_t
CGIClient::FeedHeaders(const void *data, size_t length)
try {
    assert(!parser.AreHeadersFinished());

    auto w = buffer.Write();
    assert(!w.empty());

    if (length > w.size)
        length = w.size;

    memcpy(w.data, data, length);
    buffer.Append(length);

    switch (parser.FeedHeaders(GetPool(), buffer)) {
    case Completion::DONE:
        /* the DONE status can only be triggered by new data that
           was just received; therefore, the amount of data still in
           the buffer (= response body) must be smaller */
        assert(buffer.GetAvailable() < length);

        if (!ReturnResponse())
            return 0;

        /* don't consider data still in the buffer (= response body)
           as "consumed"; the caller will attempt to submit it to the
           response body handler */
        return length - buffer.GetAvailable();

    case Completion::MORE:
        return length;

    case Completion::CLOSED:
        /* unreachable */
        assert(false);
        return 0;
    }

    /* unreachable */
    assert(false);
    return 0;
} catch (...) {
    buffer.Free();
    input.ClearAndClose();
    handler.InvokeError(std::current_exception());
    Destroy();
    return 0;
}

inline size_t
CGIClient::FeedHeadersLoop(const char *data, size_t length)
{
    assert(length > 0);
    assert(!parser.AreHeadersFinished());

    const DestructObserver destructed(*this);
    size_t consumed = 0;

    do {
        size_t nbytes = FeedHeaders(data + consumed, length - consumed);
        if (nbytes == 0)
            break;

        consumed += nbytes;
    } while (consumed < length && !parser.AreHeadersFinished());

    if (destructed)
        return 0;

    return consumed;
}

inline size_t
CGIClient::FeedHeadersCheck(const char *data, size_t length)
{
    size_t nbytes = FeedHeadersLoop(data, length);

    assert(nbytes == 0 || input.IsDefined());
    assert(nbytes == 0 ||
           !parser.AreHeadersFinished() ||
           !parser.IsEOF());

    return nbytes;
}

inline size_t
CGIClient::FeedBody(const char *data, size_t length)
{
    if (parser.IsTooMuch(length)) {
        stopwatch.RecordEvent("malformed");

        buffer.Free();
        input.ClearAndClose();

        DestroyError(std::make_exception_ptr(CgiError("too much data from CGI script")));
        return 0;
    }

    had_output = true;

    size_t nbytes = InvokeData(data, length);
    if (nbytes > 0 && parser.BodyConsumed(nbytes)) {
        stopwatch.RecordEvent("end");

        buffer.Free();
        input.ClearAndClose();
        DestroyEof();
        return 0;
    }

    return nbytes;
}

/*
 * input handler
 *
 */

size_t
CGIClient::OnData(const void *data, size_t length) noexcept
{
    assert(input.IsDefined());

    had_input = true;

    if (!parser.AreHeadersFinished()) {
        size_t nbytes = FeedHeadersCheck((const char *)data, length);

        if (nbytes > 0 && nbytes < length &&
            parser.AreHeadersFinished()) {
            /* the headers are finished; now begin sending the
               response body */
            const DestructObserver destructed(*this);
            size_t nbytes2 = FeedBody((const char *)data + nbytes,
                                      length - nbytes);
            if (nbytes2 > 0)
                /* more data was consumed */
                nbytes += nbytes2;
            else if (destructed)
                /* the connection was closed, must return 0 */
                nbytes = 0;
        }

        return nbytes;
    } else {
        return FeedBody((const char *)data, length);
    }
}

ssize_t
CGIClient::OnDirect(FdType type, int fd, size_t max_length) noexcept
{
    assert(parser.AreHeadersFinished());

    had_input = true;
    had_output = true;

    if (parser.KnownLength() &&
        (off_t)max_length > parser.GetAvailable())
        max_length = (size_t)parser.GetAvailable();

    ssize_t nbytes = InvokeDirect(type, fd, max_length);
    if (nbytes > 0 && parser.BodyConsumed(nbytes)) {
        stopwatch.RecordEvent("end");

        buffer.Free();
        input.Close();
        DestroyEof();
        return ISTREAM_RESULT_CLOSED;
    }

    return nbytes;
}

void
CGIClient::OnEof() noexcept
{
    input.Clear();

    if (!parser.AreHeadersFinished()) {
        stopwatch.RecordEvent("malformed");

        assert(!HasHandler());

        buffer.Free();

        handler.InvokeError(std::make_exception_ptr(CgiError("premature end of headers from CGI script")));
        Destroy();
    } else if (parser.DoesRequireMore()) {
        stopwatch.RecordEvent("malformed");

        buffer.Free();

        DestroyError(std::make_exception_ptr(CgiError("premature end of response body from CGI script")));
    } else {
        stopwatch.RecordEvent("end");

        buffer.Free();
        DestroyEof();
    }
}

void
CGIClient::OnError(std::exception_ptr ep) noexcept
{
    stopwatch.RecordEvent("error");

    input.Clear();

    if (!parser.AreHeadersFinished()) {
        /* the response hasn't been sent yet: notify the response
           handler */
        assert(!HasHandler());

        buffer.Free();

        handler.InvokeError(NestException(ep,
                                          std::runtime_error("CGI request body failed")));
        Destroy();
    } else {
        /* response has been sent: abort only the output stream */
        buffer.Free();
        DestroyError(ep);
    }
}

/*
 * istream implementation
 *
 */

off_t
CGIClient::_GetAvailable(bool partial) noexcept
{
    if (parser.KnownLength())
        return parser.GetAvailable();

    if (!input.IsDefined())
        return 0;

    if (in_response_callback)
        /* this condition catches the case in cgi_parse_headers():
           HttpResponseHandler::InvokeResponse() might
           recursively call istream_read(input) */
        return (off_t)-1;

    return input.GetAvailable(partial);
}

void
CGIClient::_Read() noexcept
{
    if (input.IsDefined()) {
        input.SetDirect(GetHandlerDirect());

        /* this condition catches the case in cgi_parse_headers():
           HttpResponseHandler::InvokeResponse() might
           recursively call input.Read() */
        if (in_response_callback) {
            return;
        }

        const DestructObserver destructed(*this);

        had_output = false;
        do {
            had_input = false;
            input.Read();
        } while (!destructed && input.IsDefined() && had_input && !had_output);
    }
}

void
CGIClient::_Close() noexcept
{
    buffer.Free();

    if (input.IsDefined())
        input.ClearAndClose();

    Destroy();
}

/*
 * async operation
 *
 */

void
CGIClient::Cancel() noexcept
{
    assert(input.IsDefined());

    buffer.Free();
    input.Close();
    Destroy();
}

/*
 * constructor
 *
 */

inline
CGIClient::CGIClient(struct pool &_pool, StopwatchPtr &&_stopwatch,
                     UnusedIstreamPtr _input,
                     HttpResponseHandler &_handler,
                     CancellablePointer &cancel_ptr)
    :PoolLeakDetector(_pool), Istream(_pool),
     stopwatch(std::move(_stopwatch)),
     input(std::move(_input), *this),
     buffer(fb_pool_get()),
     parser(_pool),
     handler(_handler)
{
    cancel_ptr = *this;

    input.Read();
}

void
cgi_client_new(struct pool &pool, StopwatchPtr stopwatch,
               UnusedIstreamPtr input,
               HttpResponseHandler &handler,
               CancellablePointer &cancel_ptr)
{
    NewFromPool<CGIClient>(pool, pool, std::move(stopwatch),
                           std::move(input),
                           handler, cancel_ptr);
}
<commit_msg>cgi/Client: destroy before invoking the handler<commit_after>/*
 * Copyright 2007-2019 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Client.hxx"
#include "Error.hxx"
#include "Parser.hxx"
#include "pool/pool.hxx"
#include "pool/LeakDetector.hxx"
#include "istream/Handler.hxx"
#include "istream/UnusedPtr.hxx"
#include "istream/Pointer.hxx"
#include "istream/istream_null.hxx"
#include "http/HeaderParser.hxx"
#include "stopwatch.hxx"
#include "strmap.hxx"
#include "HttpResponseHandler.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "util/Cast.hxx"
#include "util/Cancellable.hxx"
#include "util/DestructObserver.hxx"
#include "util/Exception.hxx"

#include <string.h>
#include <stdlib.h>

class CGIClient final : PoolLeakDetector, Istream, IstreamHandler, Cancellable, DestructAnchor {
    const StopwatchPtr stopwatch;

    IstreamPointer input;
    SliceFifoBuffer buffer;

    CGIParser parser;

    /**
     * This flag is true while cgi_parse_headers() is calling
     * HttpResponseHandler::InvokeResponse().  In this case,
     * istream_read(cgi->input) is already up in the stack, and must
     * not be called again.
     */
    bool in_response_callback;

    bool had_input, had_output;

    HttpResponseHandler &handler;

public:
    CGIClient(struct pool &_pool, StopwatchPtr &&_stopwatch,
              UnusedIstreamPtr _input,
              HttpResponseHandler &_handler,
              CancellablePointer &cancel_ptr);

    /**
     * @return false if the connection has been closed
     */
    bool ReturnResponse();

    /**
     * Feed data into the input buffer and continue parsing response
     * headers from it.  After this function returns, the response may
     * have been delivered to the response handler, and the caller should
     * post the rest of the specified buffer to the response body stream.
     *
     * Caller must hold pool reference.
     *
     * @return the number of bytes consumed from the specified buffer
     * (moved to the input buffer), 0 if the object has been closed
     */
    size_t FeedHeaders(const void *data, size_t length);

    /**
     * Call FeedHeaders() in a loop, to parse as much as possible.
     *
     * Caller must hold pool reference.
     */
    size_t FeedHeadersLoop(const char *data, size_t length);

    /**
     * Caller must hold pool reference.
     */
    size_t FeedHeadersCheck(const char *data, size_t length);

    size_t FeedBody(const char *data, size_t length);

    /* virtual methods from class Cancellable */
    void Cancel() noexcept override;

    /* virtual methods from class Istream */
    off_t _GetAvailable(bool partial) noexcept override;
    void _Read() noexcept override;
    void _Close() noexcept override;

    /* virtual methods from class IstreamHandler */
    size_t OnData(const void *data, size_t length) noexcept override;
    ssize_t OnDirect(FdType type, int fd, size_t max_length) noexcept override;
    void OnEof() noexcept override;
    void OnError(std::exception_ptr ep) noexcept override;
};

inline bool
CGIClient::ReturnResponse()
{
    http_status_t status = parser.GetStatus();
    StringMap &headers = parser.GetHeaders();

    if (http_status_is_empty(status)) {
        /* this response does not have a response body, as indicated
           by the HTTP status code */

        stopwatch.RecordEvent("empty");

        buffer.Free();
        input.ClearAndClose();

        auto &_handler = handler;
        Destroy();
        _handler.InvokeResponse(status, std::move(headers), UnusedIstreamPtr());
        return false;
    } else if (parser.IsEOF()) {
        /* the response body is empty */

        stopwatch.RecordEvent("empty");

        buffer.Free();
        input.ClearAndClose();
        auto &_handler = handler;
        Destroy();
        _handler.InvokeResponse(status, std::move(headers),
                                istream_null_new(GetPool()));
        return false;
    } else {
        stopwatch.RecordEvent("headers");

        const DestructObserver destructed(*this);

        in_response_callback = true;
        handler.InvokeResponse(status, std::move(headers),
                               UnusedIstreamPtr(this));
        if (destructed)
            return false;

        in_response_callback = false;
        return true;
    }
}

inline size_t
CGIClient::FeedHeaders(const void *data, size_t length)
try {
    assert(!parser.AreHeadersFinished());

    auto w = buffer.Write();
    assert(!w.empty());

    if (length > w.size)
        length = w.size;

    memcpy(w.data, data, length);
    buffer.Append(length);

    switch (parser.FeedHeaders(GetPool(), buffer)) {
    case Completion::DONE:
        /* the DONE status can only be triggered by new data that
           was just received; therefore, the amount of data still in
           the buffer (= response body) must be smaller */
        assert(buffer.GetAvailable() < length);

        if (!ReturnResponse())
            return 0;

        /* don't consider data still in the buffer (= response body)
           as "consumed"; the caller will attempt to submit it to the
           response body handler */
        return length - buffer.GetAvailable();

    case Completion::MORE:
        return length;

    case Completion::CLOSED:
        /* unreachable */
        assert(false);
        return 0;
    }

    /* unreachable */
    assert(false);
    return 0;
} catch (...) {
    buffer.Free();
    input.ClearAndClose();
    auto &_handler = handler;
    Destroy();
    _handler.InvokeError(std::current_exception());
    return 0;
}

inline size_t
CGIClient::FeedHeadersLoop(const char *data, size_t length)
{
    assert(length > 0);
    assert(!parser.AreHeadersFinished());

    const DestructObserver destructed(*this);
    size_t consumed = 0;

    do {
        size_t nbytes = FeedHeaders(data + consumed, length - consumed);
        if (nbytes == 0)
            break;

        consumed += nbytes;
    } while (consumed < length && !parser.AreHeadersFinished());

    if (destructed)
        return 0;

    return consumed;
}

inline size_t
CGIClient::FeedHeadersCheck(const char *data, size_t length)
{
    size_t nbytes = FeedHeadersLoop(data, length);

    assert(nbytes == 0 || input.IsDefined());
    assert(nbytes == 0 ||
           !parser.AreHeadersFinished() ||
           !parser.IsEOF());

    return nbytes;
}

inline size_t
CGIClient::FeedBody(const char *data, size_t length)
{
    if (parser.IsTooMuch(length)) {
        stopwatch.RecordEvent("malformed");

        buffer.Free();
        input.ClearAndClose();

        DestroyError(std::make_exception_ptr(CgiError("too much data from CGI script")));
        return 0;
    }

    had_output = true;

    size_t nbytes = InvokeData(data, length);
    if (nbytes > 0 && parser.BodyConsumed(nbytes)) {
        stopwatch.RecordEvent("end");

        buffer.Free();
        input.ClearAndClose();
        DestroyEof();
        return 0;
    }

    return nbytes;
}

/*
 * input handler
 *
 */

size_t
CGIClient::OnData(const void *data, size_t length) noexcept
{
    assert(input.IsDefined());

    had_input = true;

    if (!parser.AreHeadersFinished()) {
        size_t nbytes = FeedHeadersCheck((const char *)data, length);

        if (nbytes > 0 && nbytes < length &&
            parser.AreHeadersFinished()) {
            /* the headers are finished; now begin sending the
               response body */
            const DestructObserver destructed(*this);
            size_t nbytes2 = FeedBody((const char *)data + nbytes,
                                      length - nbytes);
            if (nbytes2 > 0)
                /* more data was consumed */
                nbytes += nbytes2;
            else if (destructed)
                /* the connection was closed, must return 0 */
                nbytes = 0;
        }

        return nbytes;
    } else {
        return FeedBody((const char *)data, length);
    }
}

ssize_t
CGIClient::OnDirect(FdType type, int fd, size_t max_length) noexcept
{
    assert(parser.AreHeadersFinished());

    had_input = true;
    had_output = true;

    if (parser.KnownLength() &&
        (off_t)max_length > parser.GetAvailable())
        max_length = (size_t)parser.GetAvailable();

    ssize_t nbytes = InvokeDirect(type, fd, max_length);
    if (nbytes > 0 && parser.BodyConsumed(nbytes)) {
        stopwatch.RecordEvent("end");

        buffer.Free();
        input.Close();
        DestroyEof();
        return ISTREAM_RESULT_CLOSED;
    }

    return nbytes;
}

void
CGIClient::OnEof() noexcept
{
    input.Clear();

    if (!parser.AreHeadersFinished()) {
        stopwatch.RecordEvent("malformed");

        assert(!HasHandler());

        buffer.Free();

        auto &_handler = handler;
        Destroy();
        _handler.InvokeError(std::make_exception_ptr(CgiError("premature end of headers from CGI script")));
    } else if (parser.DoesRequireMore()) {
        stopwatch.RecordEvent("malformed");

        buffer.Free();

        DestroyError(std::make_exception_ptr(CgiError("premature end of response body from CGI script")));
    } else {
        stopwatch.RecordEvent("end");

        buffer.Free();
        DestroyEof();
    }
}

void
CGIClient::OnError(std::exception_ptr ep) noexcept
{
    stopwatch.RecordEvent("error");

    input.Clear();

    if (!parser.AreHeadersFinished()) {
        /* the response hasn't been sent yet: notify the response
           handler */
        assert(!HasHandler());

        buffer.Free();

        auto &_handler = handler;
        Destroy();
        _handler.InvokeError(NestException(ep,
                                           std::runtime_error("CGI request body failed")));
    } else {
        /* response has been sent: abort only the output stream */
        buffer.Free();
        DestroyError(ep);
    }
}

/*
 * istream implementation
 *
 */

off_t
CGIClient::_GetAvailable(bool partial) noexcept
{
    if (parser.KnownLength())
        return parser.GetAvailable();

    if (!input.IsDefined())
        return 0;

    if (in_response_callback)
        /* this condition catches the case in cgi_parse_headers():
           HttpResponseHandler::InvokeResponse() might
           recursively call istream_read(input) */
        return (off_t)-1;

    return input.GetAvailable(partial);
}

void
CGIClient::_Read() noexcept
{
    if (input.IsDefined()) {
        input.SetDirect(GetHandlerDirect());

        /* this condition catches the case in cgi_parse_headers():
           HttpResponseHandler::InvokeResponse() might
           recursively call input.Read() */
        if (in_response_callback) {
            return;
        }

        const DestructObserver destructed(*this);

        had_output = false;
        do {
            had_input = false;
            input.Read();
        } while (!destructed && input.IsDefined() && had_input && !had_output);
    }
}

void
CGIClient::_Close() noexcept
{
    buffer.Free();

    if (input.IsDefined())
        input.ClearAndClose();

    Destroy();
}

/*
 * async operation
 *
 */

void
CGIClient::Cancel() noexcept
{
    assert(input.IsDefined());

    buffer.Free();
    input.Close();
    Destroy();
}

/*
 * constructor
 *
 */

inline
CGIClient::CGIClient(struct pool &_pool, StopwatchPtr &&_stopwatch,
                     UnusedIstreamPtr _input,
                     HttpResponseHandler &_handler,
                     CancellablePointer &cancel_ptr)
    :PoolLeakDetector(_pool), Istream(_pool),
     stopwatch(std::move(_stopwatch)),
     input(std::move(_input), *this),
     buffer(fb_pool_get()),
     parser(_pool),
     handler(_handler)
{
    cancel_ptr = *this;

    input.Read();
}

void
cgi_client_new(struct pool &pool, StopwatchPtr stopwatch,
               UnusedIstreamPtr input,
               HttpResponseHandler &handler,
               CancellablePointer &cancel_ptr)
{
    NewFromPool<CGIClient>(pool, pool, std::move(stopwatch),
                           std::move(input),
                           handler, cancel_ptr);
}
<|endoftext|>


<commit_before><commit_msg>Autocomplete popup should show up when clicking or pressing the up/down key in a text-field, even if the text-field is not empty.<commit_after><|endoftext|>


<commit_before>#ifndef VIENNAGRID_IO_SERIALIZATION_HPP
#define VIENNAGRID_IO_SERIALIZATION_HPP

/* =======================================================================
   Copyright (c) 2011-2012, Institute for Microelectronics,
                            Institute for Analysis and Scientific Computing,
                            TU Wien.

                            -----------------
                     ViennaGrid - The Vienna Grid Library
                            -----------------

   Authors:      Karl Rupp                           rupp@iue.tuwien.ac.at
                 Josef Weinbub                    weinbub@iue.tuwien.ac.at

   (A list of additional contributors can be found in the PDF manual)

   License:      MIT (X11), see file LICENSE in the base directory
======================================================================= */

/** @file serialization.hpp
 *  @brief    A domain wrapper class which models the Boost Serialization concept: http://www.boost.org/libs/serialization/
 */

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/shared_ptr.hpp>

namespace viennagrid
{
  namespace io
  {
    /** @brief Domain wrapper which models the Boost serialization concept
     *
     */
    template<typename DomainT>
    struct domain_serializer
    {
      typedef boost::shared_ptr<DomainT>                                                     DomainSPT;
    private:
      typedef typename DomainT::config_type                                                  ConfigType;
      typedef typename DomainT::segment_type                                                 SegmentType;
      typedef typename ConfigType::cell_tag                                                  CellTag;
      typedef typename viennagrid::result_of::const_ncell_range<DomainT, 0>::type            VertexRange;
      typedef typename viennagrid::result_of::iterator<VertexRange>::type                    VertexIterator;
      typedef typename viennagrid::result_of::point<ConfigType>::type                        PointType;
      typedef typename viennagrid::result_of::ncell<ConfigType, 0>::type                     VertexType;
      typedef typename viennagrid::result_of::ncell<ConfigType, CellTag::dim>::type          CellType;
      typedef typename viennagrid::result_of::ncell_range<SegmentType, CellTag::dim>::type   CellRange;
      typedef typename viennagrid::result_of::iterator<CellRange>::type                      CellIterator;
      typedef typename viennagrid::result_of::ncell_range<CellType, 0>::type                 VertexOnCellRange;
      typedef typename viennagrid::result_of::iterator<VertexOnCellRange>::type              VertexOnCellIterator;

      static const int DIMG = ConfigType::coordinate_system_tag::dim;

      friend class boost::serialization::access;

      /** @brief Save function is used to 'read' the data from the domain */
      template<class Archive>
      void save(Archive & ar, const unsigned int version) const
      {
        // -----------------------------------------------
        // the geometry is read and transmitted
        //
        std::size_t point_size = viennagrid::ncells<0>(*domainsp).size();
        ar & point_size;
        VertexRange vertices = viennagrid::ncells<0>(*domainsp);
        for (VertexIterator vit = vertices.begin();
             vit != vertices.end(); ++vit)
        {
           for(int d = 0; d < DIMG; d++) ar & vit->point()[d];
        }
        // -----------------------------------------------

        // -----------------------------------------------
        // the segment size is read and transmitted
        //
        std::size_t segment_size = (*domainsp).segments().size();
        ar & segment_size;
        // -----------------------------------------------

        // -----------------------------------------------
        // the segment specific cells are read and transmitted
        //
        for (std::size_t si = 0; si < segment_size; si++)
        {
          SegmentType & seg = (*domainsp).segments()[si];
          CellRange cells = viennagrid::ncells<CellTag::dim>(seg);

          std::size_t cell_size = viennagrid::ncells<CellTag::dim>(seg).size();
          ar & cell_size;

          for (CellIterator cit = cells.begin();
          cit != cells.end(); ++cit)
          {
            VertexOnCellRange vertices_on_cell = viennagrid::ncells<0>(*cit);

            for (VertexOnCellIterator vocit = vertices_on_cell.begin();
            vocit != vertices_on_cell.end();
            ++vocit)
            {
              std::size_t id = vocit->id();
              ar & id;
            }
          }
        }
        // -----------------------------------------------
      }

      /** @brief Load function is used to 'write' the data to the domain */
      template<class Archive>
      void load(Archive & ar, const unsigned int version)
      {
        // -----------------------------------------------
        // the geometry is received and stored
        //
        std::size_t point_size;
        ar & point_size;

        for(std::size_t i = 0; i < point_size; i++)
        {
          VertexType vertex;
          for(int d = 0; d < DIMG; d++)
            ar & vertex.point()[d];
          (*domainsp).push_back(vertex);
        }
        // -----------------------------------------------

        // -----------------------------------------------
        // the segments are received and created
        //
        std::size_t segment_size;
        ar & segment_size;
        (*domainsp).segments().resize(segment_size);
        // -----------------------------------------------

        // -----------------------------------------------
        // the segment specific cells are received and stored
        //
        for (std::size_t si = 0; si < segment_size; si++)
        {
          SegmentType & seg = (*domainsp).segments()[si];
          std::size_t cell_size;
          ar & cell_size;
          for(std::size_t ci = 0; ci < cell_size; ci++)
          {
            VertexType *vertices[viennagrid::topology::bndcells<CellTag, 0>::num];

            for (int j=0; j<viennagrid::topology::bndcells<CellTag, 0>::num; ++j)
            {
              std::size_t id;
              ar & id;
              vertices[j] = &(viennagrid::ncells<0>(*domainsp)[id]);
            }
            CellType cell;
            cell.vertices(vertices);
            seg.push_back(cell);
          }
        }
        // -----------------------------------------------
      }

      // -----------------------------------------------
      // notify Boost Serialization that the save and load
      // procedures differ
      //
      BOOST_SERIALIZATION_SPLIT_MEMBER()
      // -----------------------------------------------
    public:
      /** @brief The default constructor*/
      domain_serializer() : domainsp(new DomainT) {}

      /** @brief The constructor expects a shared pointer on a domain object and sets the state */
      domain_serializer(DomainSPT& domainsp) : domainsp(domainsp) {}

      /** @brief The load function enables to associate a domain with the serialzer after
      a serializer object has been constructed. */
      inline void load(DomainSPT other) { domainsp = other;  }

      /** @brief The get function enables to retrieve the domain pointer
      */
      inline DomainSPT get() { return domainsp; }

      /** @brief The functor returns a reference to the domain state*/
      DomainT& operator()() { return *domainsp; }

      /** @brief The state holds a shared pointer to the domain */
      DomainSPT  domainsp;
      //DomainT& domain;
    };

  } //namespace io
} //namespace viennagrid

#endif

<commit_msg>Adapted to new ViennaGrid, work in progress<commit_after>#ifndef VIENNAGRID_IO_SERIALIZATION_HPP
#define VIENNAGRID_IO_SERIALIZATION_HPP

/* =======================================================================
   Copyright (c) 2011-2012, Institute for Microelectronics,
                            Institute for Analysis and Scientific Computing,
                            TU Wien.

                            -----------------
                     ViennaGrid - The Vienna Grid Library
                            -----------------

   Authors:      Karl Rupp                           rupp@iue.tuwien.ac.at
                 Josef Weinbub                    weinbub@iue.tuwien.ac.at

   (A list of additional contributors can be found in the PDF manual)

   License:      MIT (X11), see file LICENSE in the base directory
======================================================================= */

/** @file serialization.hpp
 *  @brief    A domain wrapper class which models the Boost Serialization concept: http://www.boost.org/libs/serialization/
 */

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/shared_ptr.hpp>

namespace viennagrid
{
  namespace io
  {
    /** @brief Domain wrapper which models the Boost serialization concept
     *
     */
    template<typename DomainT, typename SegmentationT>
    struct domain_serializer
    {
      typedef boost::shared_ptr<DomainT>                                                     DomainSPT;
      typedef boost::shared_ptr<SegmentationT>                                               SegmentationSPT;

    private:
      typedef typename viennagrid::result_of::segment<SegmentationT>::type                   SegmentType;
      typedef typename viennagrid::result_of::cell_tag<DomainT>::type                        CellTag;
      typedef typename viennagrid::result_of::vertex_range<DomainT>::type                    VertexRange;
      typedef typename viennagrid::result_of::iterator<VertexRange>::type                    VertexIterator;
      typedef typename viennagrid::result_of::point<DomainT>::type                           PointType;
      typedef typename viennagrid::result_of::vertex<DomainT>::type                          VertexType;
      typedef typename viennagrid::result_of::cell<DomainT>::type                            CellType;
      typedef typename viennagrid::result_of::cell_range<SegmentType>::type                  CellRange;
      typedef typename viennagrid::result_of::iterator<CellRange>::type                      CellIterator;
      typedef typename viennagrid::result_of::vertex_range<CellType>::type                   VertexOnCellRange;
      typedef typename viennagrid::result_of::iterator<VertexOnCellRange>::type              VertexOnCellIterator;

      static const int DIMG = PointType::dim;

      friend class boost::serialization::access;

      /** @brief Save function is used to 'read' the data from the domain */
      template<class Archive>
      void save(Archive & ar, const unsigned int version) const
      {
        // -----------------------------------------------
        // the geometry is read and transmitted
        //
        std::size_t point_size = viennagrid::vertices(*domainsp).size();
        ar & point_size;
        VertexRange vertices = viennagrid::elements(*domainsp);
        for (VertexIterator vit = vertices.begin();
             vit != vertices.end(); ++vit)
        {
           for(int d = 0; d < DIMG; d++)
             ar & viennagrid::point(*vit)[d];
        }
        // -----------------------------------------------

        // -----------------------------------------------
        // the segment size is read and transmitted
        //
        std::size_t segment_size = (*domainsp).segments().size();
        ar & segment_size;
        // -----------------------------------------------

        // -----------------------------------------------
        // the segment specific cells are read and transmitted
        //
        for (std::size_t si = 0; si < segment_size; si++)
        {
          SegmentType & seg = (*domainsp).segments()[si];
          CellRange cells = viennagrid::elements(seg);

          std::size_t cell_size = viennagrid::cells(seg).size();
          ar & cell_size;

          for (CellIterator cit = cells.begin();
          cit != cells.end(); ++cit)
          {
            VertexOnCellRange vertices_on_cell = viennagrid::elements(*cit);

            for (VertexOnCellIterator vocit = vertices_on_cell.begin();
            vocit != vertices_on_cell.end();
            ++vocit)
            {
              std::size_t id = vocit->id().get();
              ar & id;
            }
          }
        }
        // -----------------------------------------------
      }

      /** @brief Load function is used to 'write' the data to the domain */
      template<class Archive>
      void load(Archive & ar, const unsigned int version)
      {
        // -----------------------------------------------
        // the geometry is received and stored
        //
        std::size_t point_size;
        ar & point_size;

        for(std::size_t i = 0; i < point_size; i++)
        {
          PointType p;
          for(int d = 0; d < DIMG; d++)
            ar & p[d];

          viennagrid::make_vertex( *domainsp, p );
        }
        // -----------------------------------------------

        // -----------------------------------------------
        // the segments are received and created
        //
        std::size_t segment_size;
        ar & segment_size;
        (*domainsp).segments().resize(segment_size);
        // -----------------------------------------------

        // -----------------------------------------------
        // the segment specific cells are received and stored
        //
        for (std::size_t si = 0; si < segment_size; si++)
        {
          SegmentType & seg = (*domainsp).segments()[si];
          std::size_t cell_size;
          ar & cell_size;
          for(std::size_t ci = 0; ci < cell_size; ci++)
          {
            VertexType *vertices[viennagrid::topology::bndcells<CellTag, 0>::num];

            for (int j=0; j<viennagrid::topology::bndcells<CellTag, 0>::num; ++j)
            {
              std::size_t id;
              ar & id;
              vertices[j] = &(viennagrid::ncells<0>(*domainsp)[id]);
            }
            CellType cell;
            cell.vertices(vertices);
            seg.push_back(cell);
          }
        }
        // -----------------------------------------------
      }

      // -----------------------------------------------
      // notify Boost Serialization that the save and load
      // procedures differ
      //
      BOOST_SERIALIZATION_SPLIT_MEMBER()
      // -----------------------------------------------
    public:
      /** @brief The default constructor*/
      domain_serializer() : domainsp(new DomainT) {}

      /** @brief The constructor expects a shared pointer on a domain object and sets the state */
      domain_serializer(DomainSPT& domainsp) : domainsp(domainsp) {}

      /** @brief The load function enables to associate a domain with the serialzer after
      a serializer object has been constructed. */
      inline void load(DomainSPT other) { domainsp = other;  }

      /** @brief The get function enables to retrieve the domain pointer
      */
      inline DomainSPT get() { return domainsp; }

      /** @brief The functor returns a reference to the domain state*/
      DomainT& operator()() { return *domainsp; }

      /** @brief The state holds a shared pointer to the domain */
      DomainSPT  domainsp;
      //DomainT& domain;
    };

  } //namespace io
} //namespace viennagrid

#endif

<|endoftext|>