<commit_before>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#ifndef POSEIDON_UTILITIES_HPP_
#define POSEIDON_UTILITIES_HPP_

#include "fwd.hpp"
#include "static/async_logger.hpp"
#include "core/abstract_timer.hpp"
#include "static/timer_driver.hpp"
#include <asteria/utilities.hpp>
#include <cstdio>

namespace poseidon {

using ::asteria::utf8_encode;
using ::asteria::utf8_decode;
using ::asteria::utf16_encode;
using ::asteria::utf16_decode;

using ::asteria::format_string;
using ::asteria::weaken_enum;
using ::asteria::generate_random_seed;
using ::asteria::format_errno;

template<typename... ParamsT>
ROCKET_NOINLINE
bool
do_xlog_format(Log_Level level, const char* file, long line, const char* func,
               const char* templ, const ParamsT&... params)
noexcept
  try {
    // Compose the message.
    ::rocket::tinyfmt_str fmt;
    format(fmt, templ, params...);  // ADL intended
    auto text = fmt.extract_string();

    // Push a new log entry.
    Async_Logger::enqueue(level, file, line, func, ::std::move(text));
    return true;
  }
  catch(exception& stdex) {
    // Ignore this exception, but print a message.
    ::std::fprintf(stderr,
        "WARNING: %s: could not format log: %s\n[exception `%s` thrown from '%s:%ld'\n",
        func, stdex.what(), typeid(stdex).name(), file, line);
    return false;
  }

// Note the format string must be a string literal.
#define POSEIDON_XLOG_(level, ...)  \
    (::poseidon::Async_Logger::is_enabled(level) &&  \
         ::poseidon::do_xlog_format(level, __FILE__, __LINE__, __func__,  \
                                    "" __VA_ARGS__))

#define POSEIDON_LOG_FATAL(...)   POSEIDON_XLOG_(::poseidon::log_level_fatal,  __VA_ARGS__)
#define POSEIDON_LOG_ERROR(...)   POSEIDON_XLOG_(::poseidon::log_level_error,  __VA_ARGS__)
#define POSEIDON_LOG_WARN(...)    POSEIDON_XLOG_(::poseidon::log_level_warn,   __VA_ARGS__)
#define POSEIDON_LOG_INFO(...)    POSEIDON_XLOG_(::poseidon::log_level_info,   __VA_ARGS__)
#define POSEIDON_LOG_DEBUG(...)   POSEIDON_XLOG_(::poseidon::log_level_debug,  __VA_ARGS__)
#define POSEIDON_LOG_TRACE(...)   POSEIDON_XLOG_(::poseidon::log_level_trace,  __VA_ARGS__)

template<typename... ParamsT>
[[noreturn]] ROCKET_NOINLINE
bool
do_xthrow_format(const char* file, long line, const char* func,
                 const char* templ, const ParamsT&... params)
  {
    // Compose the message.
    ::rocket::tinyfmt_str fmt;
    format(fmt, templ, params...);  // ADL intended
    auto text = fmt.extract_string();

    // Push a new log entry.
    if(Async_Logger::is_enabled(log_level_debug))
      Async_Logger::enqueue(log_level_debug, file, line, func, text);

    // Throw the exception.
    ::rocket::sprintf_and_throw<::std::runtime_error>(
        "%s: %s\n[thrown from '%s:%ld']",
        func, text.c_str(), file, line);
  }

#define POSEIDON_THROW(...)  \
    (::poseidon::do_xthrow_format(__FILE__, __LINE__, __func__,  \
                                  "" __VA_ARGS__))

// Creates an asynchronous timer. The timer function will be called by
// the timer thread, so thread safety must be taken into account.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer(int64_t next, int64_t period, FuncT&& func)
  {
    // This is the concrete timer class.
    struct Concrete_Timer : Abstract_Timer
      {
        typename ::std::decay<FuncT>::type m_func;

        Concrete_Timer(int64_t next, int64_t period, FuncT&& func)
          : Abstract_Timer(next, period),
            m_func(::std::forward<FuncT>(func))
          { }

        void
        do_on_async_timer(int64_t now)
        override
          { this->m_func(now);  }
      };

    // Allocate an abstract timer and insert it.
    auto timer = ::rocket::make_unique<Concrete_Timer>(next, period,
                                                       ::std::forward<FuncT>(func));
    return Timer_Driver::insert(::std::move(timer));
  }

// Creates a one-shot timer. The timer is deleted after being triggered.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer_oneshot(int64_t next, FuncT&& func)
  {
    return noadl::create_async_timer(next, 0, ::std::forward<FuncT>(func));
  }

// Creates a periodic timer.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer_periodic(int64_t period, FuncT&& func)
  {
    return noadl::create_async_timer(period, period, ::std::forward<FuncT>(func));
  }

}  // namespace asteria

#endif
<commit_msg>utilities: Minor<commit_after>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#ifndef POSEIDON_UTILITIES_HPP_
#define POSEIDON_UTILITIES_HPP_

#include "fwd.hpp"
#include "static/async_logger.hpp"
#include "core/abstract_timer.hpp"
#include "static/timer_driver.hpp"
#include <asteria/utilities.hpp>
#include <cstdio>

namespace poseidon {

using ::asteria::utf8_encode;
using ::asteria::utf8_decode;
using ::asteria::utf16_encode;
using ::asteria::utf16_decode;

using ::asteria::format_string;
using ::asteria::weaken_enum;
using ::asteria::generate_random_seed;
using ::asteria::format_errno;

template<typename... ParamsT>
ROCKET_NOINLINE
bool
do_xlog_format(Log_Level level, const char* file, long line, const char* func,
               const char* templ, const ParamsT&... params)
noexcept
  try {
    // Compose the message.
    ::rocket::tinyfmt_str fmt;
    format(fmt, templ, params...);  // ADL intended
    auto text = fmt.extract_string();

    // Push a new log entry.
    Async_Logger::enqueue(level, file, line, func, ::std::move(text));
    return true;
  }
  catch(exception& stdex) {
    // Ignore this exception, but print a message.
    ::std::fprintf(stderr,
        "WARNING: %s: could not format log: %s\n[exception `%s` thrown from '%s:%ld'\n",
        func, stdex.what(), typeid(stdex).name(), file, line);
    return false;
  }

// Note the format string must be a string literal.
#define POSEIDON_XLOG_(level, ...)  \
    (::poseidon::Async_Logger::is_enabled(level) &&  \
         ::poseidon::do_xlog_format(level, __FILE__, __LINE__, __func__,  \
                                    "" __VA_ARGS__))

#define POSEIDON_LOG_FATAL(...)   POSEIDON_XLOG_(::poseidon::log_level_fatal,  __VA_ARGS__)
#define POSEIDON_LOG_ERROR(...)   POSEIDON_XLOG_(::poseidon::log_level_error,  __VA_ARGS__)
#define POSEIDON_LOG_WARN(...)    POSEIDON_XLOG_(::poseidon::log_level_warn,   __VA_ARGS__)
#define POSEIDON_LOG_INFO(...)    POSEIDON_XLOG_(::poseidon::log_level_info,   __VA_ARGS__)
#define POSEIDON_LOG_DEBUG(...)   POSEIDON_XLOG_(::poseidon::log_level_debug,  __VA_ARGS__)
#define POSEIDON_LOG_TRACE(...)   POSEIDON_XLOG_(::poseidon::log_level_trace,  __VA_ARGS__)

template<typename... ParamsT>
[[noreturn]] ROCKET_NOINLINE
bool
do_xthrow_format(const char* file, long line, const char* func,
                 const char* templ, const ParamsT&... params)
  {
    // Compose the message.
    ::rocket::tinyfmt_str fmt;
    format(fmt, templ, params...);  // ADL intended
    auto text = fmt.extract_string();

    // Push a new log entry.
    if(Async_Logger::is_enabled(log_level_debug))
      Async_Logger::enqueue(log_level_debug, file, line, func, text);

    // Throw the exception.
    ::rocket::sprintf_and_throw<::std::runtime_error>(
        "%s: %s\n[thrown from '%s:%ld']",
        func, text.c_str(), file, line);
  }

#define POSEIDON_THROW(...)  \
    (::poseidon::do_xthrow_format(__FILE__, __LINE__, __func__,  \
                                  "" __VA_ARGS__))

// Creates an asynchronous timer. The timer function will be called by
// the timer thread, so thread safety must be taken into account.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer(int64_t next, int64_t period, FuncT&& func)
  {
    // This is the concrete timer class.
    struct Concrete_Timer : Abstract_Timer
      {
        typename ::std::decay<FuncT>::type m_func;

        explicit
        Concrete_Timer(int64_t next, int64_t period, FuncT&& func)
          : Abstract_Timer(next, period),
            m_func(::std::forward<FuncT>(func))
          { }

        void
        do_on_async_timer(int64_t now)
        override
          { this->m_func(now);  }
      };

    // Allocate an abstract timer and insert it.
    auto timer = ::rocket::make_unique<Concrete_Timer>(next, period,
                                           ::std::forward<FuncT>(func));
    return Timer_Driver::insert(::std::move(timer));
  }

// Creates a one-shot timer. The timer is deleted after being triggered.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer_oneshot(int64_t next, FuncT&& func)
  {
    return noadl::create_async_timer(next, 0, ::std::forward<FuncT>(func));
  }

// Creates a periodic timer.
template<typename FuncT>
rcptr<Abstract_Timer>
create_async_timer_periodic(int64_t period, FuncT&& func)
  {
    return noadl::create_async_timer(period, period, ::std::forward<FuncT>(func));
  }

}  // namespace asteria

#endif
<|endoftext|>


<commit_before>
#ifndef DUNE_DETAILED_DISCRETIZATIONS_ASSEMBLER_MULTISCALE_COUPLING_HH
#define DUNE_DETAILED_DISCRETIZATIONS_ASSEMBLER_MULTISCALE_COUPLING_HH

// system
#include <vector>

// dune-common
#include <dune/common/dynmatrix.hh>

namespace Dune {

namespace Detailed {

namespace Discretizations {

namespace Assembler {

namespace Multiscale {

namespace Coupling {

template <class CouplingGridPartImp, class InnerAnsatzSpaceImp, class InnerTestSpaceImp, class OuterAnsatzSpaceImp,
          class OuterTestSpaceImp>
class Primal
{
public:
  typedef CouplingGridPartImp CouplingGridPartType;

  typedef InnerAnsatzSpaceImp InnerAnsatzSpaceType;

  typedef InnerTestSpaceImp InnerTestSpaceType;

  typedef OuterAnsatzSpaceImp OuterAnsatzSpaceType;

  typedef OuterTestSpaceImp OuterTestSpaceType;

  typedef Primal<CouplingGridPartType, InnerAnsatzSpaceType, InnerTestSpaceType, OuterAnsatzSpaceType,
                 OuterTestSpaceType> ThisType;

private:
  typedef typename CouplingGridPartType::IntersectionIteratorType IntersectionIteratorType;
  typedef typename IntersectionIteratorType::Intersection IntersectionType;
  typedef typename InnerAnsatzSpaceType::RangeFieldType RangeFieldType;
  typedef Dune::DynamicMatrix<RangeFieldType> LocalMatrixType;
  typedef std::vector<std::vector<LocalMatrixType>> LocalMatricesContainerType;

  class LocalMatrixAssemblerApplication
  {
  public:
    virtual void apply(const IntersectionType& /*_intersection*/, const InnerAnsatzSpaceType& /*_innerAnsatzSpace*/,
                       const InnerTestSpaceType& /*_innerTestSpace*/, const OuterAnsatzSpaceType& /*_outerAnsatzSpace*/,
                       const OuterTestSpaceType& /*_outerTestSpace*/,
                       LocalMatricesContainerType& /*_localMatricesContainer*/) const = 0;

    virtual std::vector<unsigned int> numTmpObjectsRequired() const = 0;
  }; // class LocalOperatorApplication

  template <class LocalMatrixAssemblerType, class MatrixType>
  class LocalMatrixAssemblerApplicationWrapper : public LocalMatrixAssemblerApplication
  {
  public:
    LocalMatrixAssemblerApplicationWrapper(const Dune::shared_ptr<const LocalMatrixAssemblerType> _localMatrixAssembler,
                                           Dune::shared_ptr<MatrixType> _innerInnerMatrix,
                                           Dune::shared_ptr<MatrixType> _outerOuterMatrix,
                                           Dune::shared_ptr<MatrixType> _innerOuterMatrix,
                                           Dune::shared_ptr<MatrixType> _outerInnerMatrix)
      : localMatrixAssembler_(_localMatrixAssembler)
      , innerInnerMatrix_(_innerInnerMatrix)
      , outerOuterMatrix_(_outerOuterMatrix)
      , innerOuterMatrix_(_innerOuterMatrix)
      , outerInnerMatrix_(_outerInnerMatrix)
    {
    }

    virtual void apply(const IntersectionType& _intersection, const InnerAnsatzSpaceType& _innerAnsatzSpace,
                       const InnerTestSpaceType& _innerTestSpace, const OuterAnsatzSpaceType& _outerAnsatzSpace,
                       const OuterTestSpaceType& _outerTestSpace,
                       LocalMatricesContainerType& _localMatricesContainer) const
    {
      localMatrixAssembler_->assembleLocal(_intersection,
                                           _innerAnsatzSpace,
                                           _innerTestSpace,
                                           _outerAnsatzSpace,
                                           _outerTestSpace,
                                           *innerInnerMatrix_,
                                           *outerOuterMatrix_,
                                           *innerOuterMatrix_,
                                           *outerInnerMatrix_,
                                           _localMatricesContainer);
    } // virtual void applyLocal(...) const

    virtual std::vector<unsigned int> numTmpObjectsRequired() const
    {
      return localMatrixAssembler_->numTmpObjectsRequired();
    } // virtual std::vector< unsigned int > numTmpObjectsRequired() const

  private:
    const Dune::shared_ptr<const LocalMatrixAssemblerType> localMatrixAssembler_;
    Dune::shared_ptr<MatrixType> innerInnerMatrix_;
    Dune::shared_ptr<MatrixType> outerOuterMatrix_;
    Dune::shared_ptr<MatrixType> innerOuterMatrix_;
    Dune::shared_ptr<MatrixType> outerInnerMatrix_;
  }; // class LocalMatrixAssemblerApplicationWrapper

public:
  Primal(const CouplingGridPartType& couplingGridPart, const InnerAnsatzSpaceType& innerAnsatzSpace,
         const InnerTestSpaceType& innerTestSpace, const OuterAnsatzSpaceType& outerAnsatzSpace,
         const OuterTestSpaceType& outerTestSpace)
    : couplingGridPart_(couplingGridPart)
    , innerAnsatzSpace_(innerAnsatzSpace)
    , innerTestSpace_(innerTestSpace)
    , outerAnsatzSpace_(outerAnsatzSpace)
    , outerTestSpace_(outerTestSpace)
  {
  }

  const CouplingGridPartType& couplingGridPart() const
  {
    return couplingGridPart_;
  }

  const InnerAnsatzSpaceType& innerAnsatzSpace() const
  {
    return innerAnsatzSpace_;
  }

  const InnerTestSpaceType& innerTestSpace() const
  {
    return innerTestSpace_;
  }

  const OuterAnsatzSpaceType& outerAnsatzSpace() const
  {
    return outerAnsatzSpace_;
  }

  const OuterTestSpaceType& outerTestSpace() const
  {
    return outerTestSpace_;
  }

  template <class LocalMatrixAssemblerType, class MatrixType>
  void addLocalMatrixAssembler(const Dune::shared_ptr<const LocalMatrixAssemblerType> _localMatrixAssembler,
                               Dune::shared_ptr<MatrixType> _innerInnerMatrix,
                               Dune::shared_ptr<MatrixType> _outerOuterMatrix,
                               Dune::shared_ptr<MatrixType> _innerOuterMatrix,
                               Dune::shared_ptr<MatrixType> _outerInnerMatrix)
  {
    typedef LocalMatrixAssemblerApplicationWrapper<LocalMatrixAssemblerType, MatrixType> WrapperType;
    WrapperType* wrapper = new WrapperType(
        _localMatrixAssembler, _innerInnerMatrix, _outerOuterMatrix, _innerOuterMatrix, _outerInnerMatrix);
    localMatrixAssemblers_.push_back(wrapper);
  }

  //  template< class LocalAssemblerType, class MatrixBackendType >
  void assemble /*Matrices*/ (/*const LocalAssemblerType& localAssembler,
                        MatrixBackendType& innerInnerMatrix,
                        MatrixBackendType& innerOuterMatrix,
                        MatrixBackendType& outerInnerMatrix,
                        MatrixBackendType& outerOuterMatrix*/) const
  {
    // preparations
    typedef typename CouplingGridPartType::template Codim<0>::EntityType EntityType;
    typedef typename IntersectionType::EntityPointer EntityPointerType;
    // common tmp storage for all entities
    // * for the matrix assemblers
    std::vector<unsigned int> numberOfTmpMatricesNeeded(2, 0);
    for (unsigned int ii = 0; ii < localMatrixAssemblers_.size(); ++ii) {
      const std::vector<unsigned int> tmp = localMatrixAssemblers_[ii]->numTmpObjectsRequired();
      numberOfTmpMatricesNeeded[0]        = std::max(numberOfTmpMatricesNeeded[0], tmp[0]);
      numberOfTmpMatricesNeeded[1]        = std::max(numberOfTmpMatricesNeeded[1], tmp[1]);
    }
    std::vector<LocalMatrixType> tmpLocalAssemblerMatrices(
        numberOfTmpMatricesNeeded[0],
        LocalMatrixType(std::max(innerAnsatzSpace_.map().maxLocalSize(), outerAnsatzSpace_.map().maxLocalSize()),
                        std::max(innerTestSpace_.map().maxLocalSize(), outerTestSpace_.map().maxLocalSize()),
                        RangeFieldType(0.0)));
    std::vector<LocalMatrixType> tmpLocalOperatorMatrices(
        numberOfTmpMatricesNeeded[1],
        LocalMatrixType(std::max(innerAnsatzSpace_.map().maxLocalSize(), outerAnsatzSpace_.map().maxLocalSize()),
                        std::max(innerTestSpace_.map().maxLocalSize(), outerTestSpace_.map().maxLocalSize()),
                        RangeFieldType(0.0)));
    std::vector<std::vector<LocalMatrixType>> tmpLocalMatricesContainer;
    tmpLocalMatricesContainer.push_back(tmpLocalAssemblerMatrices);
    tmpLocalMatricesContainer.push_back(tmpLocalOperatorMatrices);
    //    // common tmp storage for all entities
    //    std::vector< unsigned int > numberTmpMatrices = localAssembler.numTmpObjectsRequired();
    //    std::vector< LocalMatrixType > tmpLocalAssemblerMatrices(numberTmpMatrices[0],
    //                                                             LocalMatrixType(std::max(innerAnsatzSpace_.map().maxLocalSize(),
    //                                                             outerAnsatzSpace_.map().maxLocalSize()),
    //                                                                             std::max(innerTestSpace_.map().maxLocalSize(),
    //                                                                             outerTestSpace_.map().maxLocalSize()),
    //                                                                             RangeFieldType(0.0)));
    //    std::vector< LocalMatrixType > tmpLocalOperatorMatrices(numberTmpMatrices[1],
    //                                                            LocalMatrixType(std::max(innerAnsatzSpace_.map().maxLocalSize(),
    //                                                            outerAnsatzSpace_.map().maxLocalSize()),
    //                                                                            std::max(innerTestSpace_.map().maxLocalSize(),
    //                                                                            outerTestSpace_.map().maxLocalSize()),
    //                                                                            RangeFieldType(0.0)));
    //    std::vector< std::vector< LocalMatrixType > > tmpLocalMatricesContainer;
    //    tmpLocalMatricesContainer.push_back(tmpLocalAssemblerMatrices);
    //    tmpLocalMatricesContainer.push_back(tmpLocalOperatorMatrices);
    // walk the coupling grid part
    for (typename CouplingGridPartType::template Codim<0>::IteratorType entityIt =
             couplingGridPart_.template begin<0>();
         entityIt != couplingGridPart_.template end<0>();
         ++entityIt) {
      const EntityType& insideEntity = *entityIt;
      // walk the intersections
      for (IntersectionIteratorType interectionIt = couplingGridPart_.ibegin(insideEntity);
           interectionIt != couplingGridPart_.iend(insideEntity);
           ++interectionIt) {
        // with a coupling grid part we can be sure to only get inner intersection (so we only need the assert, not an
        // if)
        const IntersectionType& intersection = *interectionIt;
        assert(intersection.neighbor() && !intersection.boundary());
        // call the local assembler
        // assemble local matrices
        for (unsigned int ii = 0; ii < localMatrixAssemblers_.size(); ++ii)
          localMatrixAssemblers_[ii]->apply(intersection,
                                            innerAnsatzSpace_,
                                            innerTestSpace_,
                                            outerAnsatzSpace_,
                                            outerTestSpace_,
                                            tmpLocalMatricesContainer);
      } // walk the intersections
    } // walk the coupling grid part
  } // void assembleMatrices() const

private:
  const CouplingGridPartType& couplingGridPart_;
  const InnerAnsatzSpaceType& innerAnsatzSpace_;
  const InnerTestSpaceType& innerTestSpace_;
  const OuterAnsatzSpaceType& outerAnsatzSpace_;
  const OuterTestSpaceType& outerTestSpace_;
  std::vector<LocalMatrixAssemblerApplication*> localMatrixAssemblers_;
}; // class Primal

} // namespace Coupling

} // namespace Multiscale

} // namespace Assembler

} // namespace Discretizations

} // namespace Detailed

} // namespace Dune

#endif // DUNE_DETAILED_DISCRETIZATIONS_ASSEMBLER_MULTISCALE_COUPLING_HH
<commit_msg>[assembler.multiscale.coupling]<commit_after>
#ifndef DUNE_DETAILED_DISCRETIZATIONS_ASSEMBLER_MULTISCALE_COUPLING_HH
#define DUNE_DETAILED_DISCRETIZATIONS_ASSEMBLER_MULTISCALE_COUPLING_HH

// system
#include <vector>

// dune-common
#include <dune/common/dynmatrix.hh>

namespace Dune {

namespace Detailed {

namespace Discretizations {

namespace Assembler {

namespace Multiscale {

namespace Coupling {

template <class CouplingGridPartImp, class InnerAnsatzSpaceImp, class InnerTestSpaceImp, class OuterAnsatzSpaceImp,
          class OuterTestSpaceImp>
class Primal
{
public:
  typedef CouplingGridPartImp CouplingGridPartType;

  typedef InnerAnsatzSpaceImp InnerAnsatzSpaceType;

  typedef InnerTestSpaceImp InnerTestSpaceType;

  typedef OuterAnsatzSpaceImp OuterAnsatzSpaceType;

  typedef OuterTestSpaceImp OuterTestSpaceType;

  typedef Primal<CouplingGridPartType, InnerAnsatzSpaceType, InnerTestSpaceType, OuterAnsatzSpaceType,
                 OuterTestSpaceType> ThisType;

private:
  typedef typename CouplingGridPartType::IntersectionIteratorType IntersectionIteratorType;
  typedef typename IntersectionIteratorType::Intersection IntersectionType;
  typedef typename InnerAnsatzSpaceType::RangeFieldType RangeFieldType;
  typedef Dune::DynamicMatrix<RangeFieldType> LocalMatrixType;
  typedef std::vector<std::vector<LocalMatrixType>> LocalMatricesContainerType;

  class LocalMatrixAssemblerApplication
  {
  public:
    virtual void apply(const IntersectionType& /*_intersection*/, const InnerAnsatzSpaceType& /*_innerAnsatzSpace*/,
                       const InnerTestSpaceType& /*_innerTestSpace*/, const OuterAnsatzSpaceType& /*_outerAnsatzSpace*/,
                       const OuterTestSpaceType& /*_outerTestSpace*/,
                       LocalMatricesContainerType& /*_localMatricesContainer*/) const = 0;

    virtual std::vector<unsigned int> numTmpObjectsRequired() const = 0;
  }; // class LocalOperatorApplication

  template <class LocalMatrixAssemblerType, class MatrixType>
  class LocalMatrixAssemblerApplicationWrapper : public LocalMatrixAssemblerApplication
  {
  public:
    LocalMatrixAssemblerApplicationWrapper(const Dune::shared_ptr<const LocalMatrixAssemblerType> _localMatrixAssembler,
                                           Dune::shared_ptr<MatrixType> _innerInnerMatrix,
                                           Dune::shared_ptr<MatrixType> _outerOuterMatrix,
                                           Dune::shared_ptr<MatrixType> _innerOuterMatrix,
                                           Dune::shared_ptr<MatrixType> _outerInnerMatrix)
      : localMatrixAssembler_(_localMatrixAssembler)
      , innerInnerMatrix_(_innerInnerMatrix)
      , outerOuterMatrix_(_outerOuterMatrix)
      , innerOuterMatrix_(_innerOuterMatrix)
      , outerInnerMatrix_(_outerInnerMatrix)
    {
    }

    virtual void apply(const IntersectionType& _intersection, const InnerAnsatzSpaceType& _innerAnsatzSpace,
                       const InnerTestSpaceType& _innerTestSpace, const OuterAnsatzSpaceType& _outerAnsatzSpace,
                       const OuterTestSpaceType& _outerTestSpace,
                       LocalMatricesContainerType& _localMatricesContainer) const
    {
      localMatrixAssembler_->assembleLocal(_intersection,
                                           _innerAnsatzSpace,
                                           _innerTestSpace,
                                           _outerAnsatzSpace,
                                           _outerTestSpace,
                                           *innerInnerMatrix_,
                                           *outerOuterMatrix_,
                                           *innerOuterMatrix_,
                                           *outerInnerMatrix_,
                                           _localMatricesContainer);
    } // virtual void applyLocal(...) const

    virtual std::vector<unsigned int> numTmpObjectsRequired() const
    {
      return localMatrixAssembler_->numTmpObjectsRequired();
    } // virtual std::vector< unsigned int > numTmpObjectsRequired() const

  private:
    const Dune::shared_ptr<const LocalMatrixAssemblerType> localMatrixAssembler_;
    Dune::shared_ptr<MatrixType> innerInnerMatrix_;
    Dune::shared_ptr<MatrixType> outerOuterMatrix_;
    Dune::shared_ptr<MatrixType> innerOuterMatrix_;
    Dune::shared_ptr<MatrixType> outerInnerMatrix_;
  }; // class LocalMatrixAssemblerApplicationWrapper

public:
  Primal(const CouplingGridPartType& couplingGridPart, const InnerAnsatzSpaceType& innerAnsatzSpace,
         const InnerTestSpaceType& innerTestSpace, const OuterAnsatzSpaceType& outerAnsatzSpace,
         const OuterTestSpaceType& outerTestSpace)
    : couplingGridPart_(couplingGridPart)
    , innerAnsatzSpace_(innerAnsatzSpace)
    , innerTestSpace_(innerTestSpace)
    , outerAnsatzSpace_(outerAnsatzSpace)
    , outerTestSpace_(outerTestSpace)
  {
  }

  const CouplingGridPartType& couplingGridPart() const
  {
    return couplingGridPart_;
  }

  const InnerAnsatzSpaceType& innerAnsatzSpace() const
  {
    return innerAnsatzSpace_;
  }

  const InnerTestSpaceType& innerTestSpace() const
  {
    return innerTestSpace_;
  }

  const OuterAnsatzSpaceType& outerAnsatzSpace() const
  {
    return outerAnsatzSpace_;
  }

  const OuterTestSpaceType& outerTestSpace() const
  {
    return outerTestSpace_;
  }

  template <class LocalMatrixAssemblerType, class MatrixType>
  void addLocalMatrixAssembler(const Dune::shared_ptr<const LocalMatrixAssemblerType> _localMatrixAssembler,
                               Dune::shared_ptr<MatrixType> _innerInnerMatrix,
                               Dune::shared_ptr<MatrixType> _outerOuterMatrix,
                               Dune::shared_ptr<MatrixType> _innerOuterMatrix,
                               Dune::shared_ptr<MatrixType> _outerInnerMatrix)
  {
    typedef LocalMatrixAssemblerApplicationWrapper<LocalMatrixAssemblerType, MatrixType> WrapperType;
    WrapperType* wrapper = new WrapperType(
        _localMatrixAssembler, _innerInnerMatrix, _outerOuterMatrix, _innerOuterMatrix, _outerInnerMatrix);
    localMatrixAssemblers_.push_back(wrapper);
  }

  //  template< class LocalAssemblerType, class MatrixBackendType >
  void assemble /*Matrices*/ (/*const LocalAssemblerType& localAssembler,
                        MatrixBackendType& innerInnerMatrix,
                        MatrixBackendType& innerOuterMatrix,
                        MatrixBackendType& outerInnerMatrix,
                        MatrixBackendType& outerOuterMatrix*/) const
  {
    // preparations
    typedef typename CouplingGridPartType::template Codim<0>::EntityType EntityType;
    typedef typename IntersectionType::EntityPointer EntityPointerType;
    // common tmp storage for all entities
    // * for the matrix assemblers
    std::vector<unsigned int> numberOfTmpMatricesNeeded(2, 0);
    for (unsigned int ii = 0; ii < localMatrixAssemblers_.size(); ++ii) {
      const std::vector<unsigned int> tmp = localMatrixAssemblers_[ii]->numTmpObjectsRequired();
      numberOfTmpMatricesNeeded[0]        = std::max(numberOfTmpMatricesNeeded[0], tmp[0]);
      numberOfTmpMatricesNeeded[1]        = std::max(numberOfTmpMatricesNeeded[1], tmp[1]);
    }
    std::vector<LocalMatrixType> tmpLocalAssemblerMatrices(
        numberOfTmpMatricesNeeded[0],
        LocalMatrixType(std::max(innerAnsatzSpace_.map().maxLocalSize(), outerAnsatzSpace_.map().maxLocalSize()),
                        std::max(innerTestSpace_.map().maxLocalSize(), outerTestSpace_.map().maxLocalSize()),
                        RangeFieldType(0.0)));
    std::vector<LocalMatrixType> tmpLocalOperatorMatrices(
        numberOfTmpMatricesNeeded[1],
        LocalMatrixType(std::max(innerAnsatzSpace_.map().maxLocalSize(), outerAnsatzSpace_.map().maxLocalSize()),
                        std::max(innerTestSpace_.map().maxLocalSize(), outerTestSpace_.map().maxLocalSize()),
                        RangeFieldType(0.0)));
    std::vector<std::vector<LocalMatrixType>> tmpLocalMatricesContainer;
    tmpLocalMatricesContainer.push_back(tmpLocalAssemblerMatrices);
    tmpLocalMatricesContainer.push_back(tmpLocalOperatorMatrices);
    //    // common tmp storage for all entities
    //    std::vector< unsigned int > numberTmpMatrices = localAssembler.numTmpObjectsRequired();
    //    std::vector< LocalMatrixType > tmpLocalAssemblerMatrices(numberTmpMatrices[0],
    //                                                             LocalMatrixType(std::max(innerAnsatzSpace_.map().maxLocalSize(),
    //                                                             outerAnsatzSpace_.map().maxLocalSize()),
    //                                                                             std::max(innerTestSpace_.map().maxLocalSize(),
    //                                                                             outerTestSpace_.map().maxLocalSize()),
    //                                                                             RangeFieldType(0.0)));
    //    std::vector< LocalMatrixType > tmpLocalOperatorMatrices(numberTmpMatrices[1],
    //                                                            LocalMatrixType(std::max(innerAnsatzSpace_.map().maxLocalSize(),
    //                                                            outerAnsatzSpace_.map().maxLocalSize()),
    //                                                                            std::max(innerTestSpace_.map().maxLocalSize(),
    //                                                                            outerTestSpace_.map().maxLocalSize()),
    //                                                                            RangeFieldType(0.0)));
    //    std::vector< std::vector< LocalMatrixType > > tmpLocalMatricesContainer;
    //    tmpLocalMatricesContainer.push_back(tmpLocalAssemblerMatrices);
    //    tmpLocalMatricesContainer.push_back(tmpLocalOperatorMatrices);
    // walk the coupling grid part
    for (typename CouplingGridPartType::template Codim<0>::IteratorType entityIt =
             couplingGridPart_.template begin<0>();
         entityIt != couplingGridPart_.template end<0>();
         ++entityIt) {
      const EntityType& insideEntity = *entityIt;
      // walk the intersections
      for (IntersectionIteratorType interectionIt = couplingGridPart_.ibegin(insideEntity);
           interectionIt != couplingGridPart_.iend(insideEntity);
           ++interectionIt) {
        // with a coupling grid part we can be sure to only get inner intersection (so we only need the assert, not an
        // if)
        const IntersectionType& intersection = *interectionIt;
        assert(intersection.neighbor() && !intersection.boundary());
        // call the local assembler
        for (unsigned int ii = 0; ii < localMatrixAssemblers_.size(); ++ii)
          localMatrixAssemblers_[ii]->apply(intersection,
                                            innerAnsatzSpace_,
                                            innerTestSpace_,
                                            outerAnsatzSpace_,
                                            outerTestSpace_,
                                            tmpLocalMatricesContainer);
      } // walk the intersections
    } // walk the coupling grid part
  } // void assembleMatrices() const

private:
  const CouplingGridPartType& couplingGridPart_;
  const InnerAnsatzSpaceType& innerAnsatzSpace_;
  const InnerTestSpaceType& innerTestSpace_;
  const OuterAnsatzSpaceType& outerAnsatzSpace_;
  const OuterTestSpaceType& outerTestSpace_;
  std::vector<LocalMatrixAssemblerApplication*> localMatrixAssemblers_;
}; // class Primal

} // namespace Coupling

} // namespace Multiscale

} // namespace Assembler

} // namespace Discretizations

} // namespace Detailed

} // namespace Dune

#endif // DUNE_DETAILED_DISCRETIZATIONS_ASSEMBLER_MULTISCALE_COUPLING_HH
<|endoftext|>


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

#include "StateUpdater.h"
#include "AssetVersionD.h"

using namespace boost;
using namespace std;

// The depth_first_search function needs a way to map vertices to indexes. We
// store a unique index inside each vertex; the code below provides a way for
// boost to access them. These must be defined before including
// depth_first_search.hpp.
template <class Graph>
class InNodeVertexIndexMap {
  public:
    typedef readable_property_map_tag category;
    typedef size_t value_type;
    typedef value_type reference;
    typedef typename Graph::vertex_descriptor key_type;

    InNodeVertexIndexMap(const Graph & graph) : graph(graph) {};
    const Graph & graph;
};

namespace boost {
  template<>
  struct property_map<StateUpdater::TreeType, vertex_index_t> {
    typedef InNodeVertexIndexMap<StateUpdater::TreeType> const_type;
  };

  template<class Graph>
  InNodeVertexIndexMap<Graph> get(vertex_index_t, const Graph & graph) {
    return InNodeVertexIndexMap<Graph>(graph);
  }

  template<class Graph>
  typename InNodeVertexIndexMap<Graph>::value_type get(
      const InNodeVertexIndexMap<Graph> & map,
      typename InNodeVertexIndexMap<Graph>::key_type vertex) {
    return map.graph[vertex].index;
  }
}

#include <boost/graph/depth_first_search.hpp>

StateUpdater::TreeType::vertex_descriptor
StateUpdater::BuildTree(const SharedString & ref) {
  VertexMap vertices;
  size_t index = 0;
  list<TreeType::vertex_descriptor> toFillIn, toFillInNext;
  // First create an empty vertex for the provided asset. Then fill it in,
  // which includes adding its connections to other assets. Every time we fill
  // in a node we will get new assets to add to the tree until all assets have
  // been added. This basically builds the tree using a breadth first search,
  // which allows us to keep memory usage (relatively) low by not forcing
  // assets to stay in the cache and limiting the size of the toFillIn and
  // toFillInNext lists.
  auto myVertex = AddEmptyVertex(ref, vertices, index, toFillIn);
  while (toFillIn.size() > 0) {
    for (auto vertex : toFillIn) {
      FillInVertex(vertex, vertices, index, toFillInNext);
    }
    toFillIn = std::move(toFillInNext);
    toFillInNext.clear();
  }
  return myVertex;
}

// Creates an "empty" node for this asset if it has not already been added to
// the tree. The node has a default state and doesn't include links to
// inputs/children/etc. The vertex must be "filled in" by calling FillInVertex
// before it can be used.
StateUpdater::TreeType::vertex_descriptor
StateUpdater::AddEmptyVertex(
    const SharedString & ref,
    VertexMap & vertices,
    size_t & index,
    list<TreeType::vertex_descriptor> & toFillIn) {
  auto myVertexIter = vertices.find(ref);
  if (myVertexIter == vertices.end()) {
    // I'm not in the graph yet, so make a new empty vertex and let the caller
    // know we need to load it with the correct information
    auto myVertex = add_vertex(tree);
    tree[myVertex] = {ref, AssetDefs::New, index};
    ++index;
    vertices[ref] = myVertex;
    toFillIn.push_back(myVertex);
    return myVertex;
  }
  else {
    // I'm already in the graph, so just return my vertex descriptor.
    return myVertexIter->second;
  }
}

// "Fills in" an existing vertex with the state of an asset and its connections
// to other assets. Adds any new nodes that need to be filled in to toFillIn.
void StateUpdater::FillInVertex(
    TreeType::vertex_descriptor myVertex,
    VertexMap & vertices,
    size_t & index,
    list<TreeType::vertex_descriptor> & toFillIn) {
  MutableAssetVersionD version(tree[myVertex].name);
  tree[myVertex].state = version->state;
  vector<SharedString> dependents;
  version->DependentChildren(dependents);
  // Add the dependent children first. When we add the children next it will
  // skip any that were already added
  for (const auto & dep : dependents) {
    auto depVertex = AddEmptyVertex(dep, vertices, index, toFillIn);
    AddEdge(myVertex, depVertex, {DEPENDENT_CHILD});
  }
  for (const auto & child : version->children) {
    auto childVertex = AddEmptyVertex(child, vertices, index, toFillIn);
    AddEdge(myVertex, childVertex, {CHILD});
  }
  for (const auto & input : version->inputs) {
    auto inputVertex = AddEmptyVertex(input, vertices, index, toFillIn);
    AddEdge(myVertex, inputVertex, {INPUT});
  }
  for (const auto & parent : version->parents) {
    auto parentVertex = AddEmptyVertex(parent, vertices, index, toFillIn);
    AddEdge(parentVertex, myVertex, {CHILD});
  }
  for (const auto & listener : version->listeners) {
    auto listenerVertex = AddEmptyVertex(listener, vertices, index, toFillIn);
    AddEdge(listenerVertex, myVertex, {INPUT});
  }
}

void StateUpdater::AddEdge(
    TreeType::vertex_descriptor from,
    TreeType::vertex_descriptor to,
    AssetEdge data) {
  auto edgeData = add_edge(from, to, tree);
  // If this is a new edge, set the edge data. Also, if this is a dependent
  // child it may have been added previously as a "normal" child, so update
  // the data in that case also.
  if (edgeData.second || data.type == DEPENDENT_CHILD) {
    tree[edgeData.first] = data;
  }
}

void StateUpdater::SetStateForRefAndDependents(
    const SharedString & ref,
    AssetDefs::State newState,
    std::function<bool(AssetDefs::State)> updateStatePredicate) {
  auto refVertex = BuildTree(ref);
  SetStateForVertexAndDependents(refVertex, newState, updateStatePredicate);
}

void StateUpdater::SetStateForVertexAndDependents(
    TreeType::vertex_descriptor vertex,
    AssetDefs::State newState,
    std::function<bool(AssetDefs::State)> updateStatePredicate) {
  if (updateStatePredicate(tree[vertex].state)) {
    {
      // Limit the scope of the MutableAssetVersionD so that we release it
      // as quickly as possible.
      MutableAssetVersionD version(tree[vertex].name);
      // Set the state. The OnStateChange handler will take care
      // of stopping any running tasks, etc
      // false -> don't send notifications about the new state because we
      // will change it soon.
      version->SetMyStateOnly(newState, false);
    }
    auto edgeIters = out_edges(vertex, tree);
    auto edgeBegin = edgeIters.first;
    auto edgeEnd = edgeIters.second;
    for (auto i = edgeBegin; i != edgeEnd; ++i) {
      if (tree[*i].type == DEPENDENT_CHILD) {
        SetStateForVertexAndDependents(target(*i, tree), newState, updateStatePredicate);
      }
    }
  }
}

class StateUpdater::UpdateStateVisitor : public default_dfs_visitor {
  private:
    class InputStates {
      private:
        uint numinputs = 0;
        uint numgood = 0;
        uint numblocking = 0;
        uint numoffline = 0;
      public:
        void Add(AssetDefs::State inputState) {
          ++numinputs;
          if (inputState == AssetDefs::Succeeded) {
            ++numgood;
          } else if (inputState == AssetDefs::Offline) {
            ++numblocking;
            ++numoffline;
          } else if (inputState & (AssetDefs::Blocked |
                                   AssetDefs::Failed |
                                   AssetDefs::Canceled |
                                   AssetDefs::Bad)) {
            ++numblocking;
          }
        }
        void GetOutputs(AssetDefs::State & stateByInputs, bool & blockersAreOffline, uint32 & numWaitingFor) {
          if (numinputs == numgood) {
            stateByInputs = AssetDefs::Queued;
          } else if (numblocking) {
            stateByInputs = AssetDefs::Blocked;
          } else {
            stateByInputs = AssetDefs::Waiting;
          }

          blockersAreOffline = (numblocking == numoffline);

          if (stateByInputs == AssetDefs::Waiting) {
            numWaitingFor = (numinputs - numgood);
          } else {
            numWaitingFor = 0;
          }
        }
    };
    class ChildStates {
      private:
        uint numkids = 0;
        uint numgood = 0;
        uint numblocking = 0;
        uint numinprog = 0;
        uint numfailed = 0;
      public:
        void Add(AssetDefs::State childState) {
          ++numkids;
          if (childState == AssetDefs::Succeeded) {
            ++numgood;
          } else if (childState == AssetDefs::Failed) {
            ++numfailed;
          } else if (childState == AssetDefs::InProgress) {
            ++numinprog;
          } else if (childState & (AssetDefs::Blocked  |
                                   AssetDefs::Canceled |
                                   AssetDefs::Offline  |
                                   AssetDefs::Bad)) {
            ++numblocking;
          }
        }
        void GetOutputs(AssetDefs::State & stateByChildren) {
          if (numkids == numgood) {
            stateByChildren = AssetDefs::Succeeded;
          } else if (numblocking || numfailed) {
            stateByChildren = AssetDefs::Blocked;
          } else if (numgood || numinprog) {
            stateByChildren = AssetDefs::InProgress;
          } else {
            stateByChildren = AssetDefs::Queued;
          }
        }
    };

    void CalcStateByInputsAndChildren(
        StateUpdater::TreeType::vertex_descriptor vertex,
        const StateUpdater::TreeType & tree,
        AssetDefs::State &stateByInputs,
        AssetDefs::State &stateByChildren,
        bool & blockersAreOffline,
        uint32 & numWaitingFor) const {
      InputStates inputStates;
      ChildStates childStates;

      auto edgeIters = out_edges(vertex, tree);
      auto edgeBegin = edgeIters.first;
      auto edgeEnd = edgeIters.second;
      for (auto i = edgeBegin; i != edgeEnd; ++i) {
        StateUpdater::DependencyType type = tree[*i].type;
        StateUpdater::TreeType::vertex_descriptor dep = target(*i, tree);
        AssetDefs::State depState = tree[dep].state;
        switch(type) {
          case StateUpdater::INPUT:
            inputStates.Add(depState);
            break;
          case StateUpdater::CHILD:
          case StateUpdater::DEPENDENT_CHILD:
            childStates.Add(depState);
            break;
        }
      }

      inputStates.GetOutputs(stateByInputs, blockersAreOffline, numWaitingFor);
      childStates.GetOutputs(stateByChildren);
    }
  public:
    // Update the state of an asset after we've updated the state of its
    // inputs and children.
    virtual void finish_vertex(
        StateUpdater::TreeType::vertex_descriptor vertex,
        const StateUpdater::TreeType & tree) const {
      MutableAssetVersionD version(tree[vertex].name);
      if (!version->NeedComputeState()) return;
      AssetDefs::State stateByInputs;
      AssetDefs::State stateByChildren;
      bool blockersAreOffline;
      uint32 numWaitingFor;
      CalcStateByInputsAndChildren(vertex, tree, stateByInputs, stateByChildren, blockersAreOffline, numWaitingFor);
      AssetDefs::State newState;
      newState = version->CalcStateByInputsAndChildren(stateByInputs, stateByChildren, blockersAreOffline, numWaitingFor);
      // Set the state and send notifications but don't propagate the change
      // (we will take care of propagation during the graph traversal).
      version->SetMyStateOnly(newState);
      // Update the state in the tree because other assets may need it to compute
      // their own states. Use the state from the version because setting the
      // state can sometimes trigger additional state changes.
      const_cast<StateUpdater::TreeType&>(tree)[vertex].state = version->state;
    }
};

void StateUpdater::RecalculateStates() {
  // Possible optimization: Many assets have significant overlap in their
  // inputs. It might save time if we could calculate the overlapping state
  // only once.
  depth_first_search(tree, visitor(UpdateStateVisitor()));
}
<commit_msg>Comments<commit_after>/*
 * Copyright 2019 The Open GEE Contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "StateUpdater.h"
#include "AssetVersionD.h"

using namespace boost;
using namespace std;

// The depth_first_search function needs a way to map vertices to indexes. We
// store a unique index inside each vertex; the code below provides a way for
// boost to access them. These must be defined before including
// depth_first_search.hpp.
template <class Graph>
class InNodeVertexIndexMap {
  public:
    typedef readable_property_map_tag category;
    typedef size_t value_type;
    typedef value_type reference;
    typedef typename Graph::vertex_descriptor key_type;

    InNodeVertexIndexMap(const Graph & graph) : graph(graph) {};
    const Graph & graph;
};

namespace boost {
  template<>
  struct property_map<StateUpdater::TreeType, vertex_index_t> {
    typedef InNodeVertexIndexMap<StateUpdater::TreeType> const_type;
  };

  template<class Graph>
  InNodeVertexIndexMap<Graph> get(vertex_index_t, const Graph & graph) {
    return InNodeVertexIndexMap<Graph>(graph);
  }

  template<class Graph>
  typename InNodeVertexIndexMap<Graph>::value_type get(
      const InNodeVertexIndexMap<Graph> & map,
      typename InNodeVertexIndexMap<Graph>::key_type vertex) {
    return map.graph[vertex].index;
  }
}

#include <boost/graph/depth_first_search.hpp>

StateUpdater::TreeType::vertex_descriptor
StateUpdater::BuildTree(const SharedString & ref) {
  VertexMap vertices;
  size_t index = 0;
  list<TreeType::vertex_descriptor> toFillIn, toFillInNext;
  // First create an empty vertex for the provided asset. Then fill it in,
  // which includes adding its connections to other assets. Every time we fill
  // in a node we will get new assets to add to the tree until all assets have
  // been added. This basically builds the tree using a breadth first search,
  // which allows us to keep memory usage (relatively) low by not forcing
  // assets to stay in the cache and limiting the size of the toFillIn and
  // toFillInNext lists.
  auto myVertex = AddEmptyVertex(ref, vertices, index, toFillIn);
  while (toFillIn.size() > 0) {
    for (auto vertex : toFillIn) {
      FillInVertex(vertex, vertices, index, toFillInNext);
    }
    toFillIn = std::move(toFillInNext);
    toFillInNext.clear();
  }
  return myVertex;
}

// Creates an "empty" node for this asset if it has not already been added to
// the tree. The node has a default state and doesn't include links to
// inputs/children/etc. The vertex must be "filled in" by calling FillInVertex
// before it can be used.
StateUpdater::TreeType::vertex_descriptor
StateUpdater::AddEmptyVertex(
    const SharedString & ref,
    VertexMap & vertices,
    size_t & index,
    list<TreeType::vertex_descriptor> & toFillIn) {
  auto myVertexIter = vertices.find(ref);
  if (myVertexIter == vertices.end()) {
    // I'm not in the graph yet, so make a new empty vertex and let the caller
    // know we need to load it with the correct information
    auto myVertex = add_vertex(tree);
    tree[myVertex] = {ref, AssetDefs::New, index};
    ++index;
    vertices[ref] = myVertex;
    toFillIn.push_back(myVertex);
    return myVertex;
  }
  else {
    // I'm already in the graph, so just return my vertex descriptor.
    return myVertexIter->second;
  }
}

// "Fills in" an existing vertex with the state of an asset and its connections
// to other assets. Adds any new nodes that need to be filled in to toFillIn.
void StateUpdater::FillInVertex(
    TreeType::vertex_descriptor myVertex,
    VertexMap & vertices,
    size_t & index,
    list<TreeType::vertex_descriptor> & toFillIn) {
  // TODO: see if there's a way to do this that doesn't require
  // making the asset mutable.
  MutableAssetVersionD version(tree[myVertex].name);
  tree[myVertex].state = version->state;
  vector<SharedString> dependents;
  version->DependentChildren(dependents);
  // Add the dependent children first. When we add the children next it will
  // skip any that were already added
  for (const auto & dep : dependents) {
    auto depVertex = AddEmptyVertex(dep, vertices, index, toFillIn);
    AddEdge(myVertex, depVertex, {DEPENDENT_CHILD});
  }
  for (const auto & child : version->children) {
    auto childVertex = AddEmptyVertex(child, vertices, index, toFillIn);
    AddEdge(myVertex, childVertex, {CHILD});
  }
  for (const auto & input : version->inputs) {
    auto inputVertex = AddEmptyVertex(input, vertices, index, toFillIn);
    AddEdge(myVertex, inputVertex, {INPUT});
  }
  for (const auto & parent : version->parents) {
    auto parentVertex = AddEmptyVertex(parent, vertices, index, toFillIn);
    AddEdge(parentVertex, myVertex, {CHILD});
  }
  for (const auto & listener : version->listeners) {
    auto listenerVertex = AddEmptyVertex(listener, vertices, index, toFillIn);
    AddEdge(listenerVertex, myVertex, {INPUT});
  }
}

void StateUpdater::AddEdge(
    TreeType::vertex_descriptor from,
    TreeType::vertex_descriptor to,
    AssetEdge data) {
  auto edgeData = add_edge(from, to, tree);
  // If this is a new edge, set the edge data. Also, if this is a dependent
  // child it may have been added previously as a "normal" child, so update
  // the data in that case also.
  if (edgeData.second || data.type == DEPENDENT_CHILD) {
    tree[edgeData.first] = data;
  }
}

void StateUpdater::SetStateForRefAndDependents(
    const SharedString & ref,
    AssetDefs::State newState,
    std::function<bool(AssetDefs::State)> updateStatePredicate) {
  auto refVertex = BuildTree(ref);
  SetStateForVertexAndDependents(refVertex, newState, updateStatePredicate);
}

void StateUpdater::SetStateForVertexAndDependents(
    TreeType::vertex_descriptor vertex,
    AssetDefs::State newState,
    std::function<bool(AssetDefs::State)> updateStatePredicate) {
  if (updateStatePredicate(tree[vertex].state)) {
    {
      // Limit the scope of the MutableAssetVersionD so that we release it
      // as quickly as possible.
      MutableAssetVersionD version(tree[vertex].name);
      // Set the state. The OnStateChange handler will take care
      // of stopping any running tasks, etc
      // false -> don't send notifications about the new state because we
      // will change it soon.
      version->SetMyStateOnly(newState, false);
    }
    auto edgeIters = out_edges(vertex, tree);
    auto edgeBegin = edgeIters.first;
    auto edgeEnd = edgeIters.second;
    for (auto i = edgeBegin; i != edgeEnd; ++i) {
      if (tree[*i].type == DEPENDENT_CHILD) {
        SetStateForVertexAndDependents(target(*i, tree), newState, updateStatePredicate);
      }
    }
  }
}

class StateUpdater::UpdateStateVisitor : public default_dfs_visitor {
  private:
    class InputStates {
      private:
        uint numinputs = 0;
        uint numgood = 0;
        uint numblocking = 0;
        uint numoffline = 0;
      public:
        void Add(AssetDefs::State inputState) {
          ++numinputs;
          if (inputState == AssetDefs::Succeeded) {
            ++numgood;
          } else if (inputState == AssetDefs::Offline) {
            ++numblocking;
            ++numoffline;
          } else if (inputState & (AssetDefs::Blocked |
                                   AssetDefs::Failed |
                                   AssetDefs::Canceled |
                                   AssetDefs::Bad)) {
            ++numblocking;
          }
        }
        void GetOutputs(AssetDefs::State & stateByInputs, bool & blockersAreOffline, uint32 & numWaitingFor) {
          if (numinputs == numgood) {
            stateByInputs = AssetDefs::Queued;
          } else if (numblocking) {
            stateByInputs = AssetDefs::Blocked;
          } else {
            stateByInputs = AssetDefs::Waiting;
          }

          blockersAreOffline = (numblocking == numoffline);

          if (stateByInputs == AssetDefs::Waiting) {
            numWaitingFor = (numinputs - numgood);
          } else {
            numWaitingFor = 0;
          }
        }
    };
    class ChildStates {
      private:
        uint numkids = 0;
        uint numgood = 0;
        uint numblocking = 0;
        uint numinprog = 0;
        uint numfailed = 0;
      public:
        void Add(AssetDefs::State childState) {
          ++numkids;
          if (childState == AssetDefs::Succeeded) {
            ++numgood;
          } else if (childState == AssetDefs::Failed) {
            ++numfailed;
          } else if (childState == AssetDefs::InProgress) {
            ++numinprog;
          } else if (childState & (AssetDefs::Blocked  |
                                   AssetDefs::Canceled |
                                   AssetDefs::Offline  |
                                   AssetDefs::Bad)) {
            ++numblocking;
          }
        }
        void GetOutputs(AssetDefs::State & stateByChildren) {
          if (numkids == numgood) {
            stateByChildren = AssetDefs::Succeeded;
          } else if (numblocking || numfailed) {
            stateByChildren = AssetDefs::Blocked;
          } else if (numgood || numinprog) {
            stateByChildren = AssetDefs::InProgress;
          } else {
            stateByChildren = AssetDefs::Queued;
          }
        }
    };

    void CalcStateByInputsAndChildren(
        StateUpdater::TreeType::vertex_descriptor vertex,
        const StateUpdater::TreeType & tree,
        AssetDefs::State &stateByInputs,
        AssetDefs::State &stateByChildren,
        bool & blockersAreOffline,
        uint32 & numWaitingFor) const {
      InputStates inputStates;
      ChildStates childStates;

      auto edgeIters = out_edges(vertex, tree);
      auto edgeBegin = edgeIters.first;
      auto edgeEnd = edgeIters.second;
      for (auto i = edgeBegin; i != edgeEnd; ++i) {
        StateUpdater::DependencyType type = tree[*i].type;
        StateUpdater::TreeType::vertex_descriptor dep = target(*i, tree);
        AssetDefs::State depState = tree[dep].state;
        switch(type) {
          case StateUpdater::INPUT:
            inputStates.Add(depState);
            break;
          case StateUpdater::CHILD:
          case StateUpdater::DEPENDENT_CHILD:
            childStates.Add(depState);
            break;
        }
      }

      inputStates.GetOutputs(stateByInputs, blockersAreOffline, numWaitingFor);
      childStates.GetOutputs(stateByChildren);
    }
  public:
    // Update the state of an asset after we've updated the state of its
    // inputs and children.
    virtual void finish_vertex(
        StateUpdater::TreeType::vertex_descriptor vertex,
        const StateUpdater::TreeType & tree) const {
      MutableAssetVersionD version(tree[vertex].name);
      if (!version->NeedComputeState()) return;
      AssetDefs::State stateByInputs;
      AssetDefs::State stateByChildren;
      bool blockersAreOffline;
      uint32 numWaitingFor;
      CalcStateByInputsAndChildren(vertex, tree, stateByInputs, stateByChildren, blockersAreOffline, numWaitingFor);
      AssetDefs::State newState;
      newState = version->CalcStateByInputsAndChildren(stateByInputs, stateByChildren, blockersAreOffline, numWaitingFor);
      // Set the state and send notifications but don't propagate the change
      // (we will take care of propagation during the graph traversal).
      version->SetMyStateOnly(newState);
      // Update the state in the tree because other assets may need it to compute
      // their own states. Use the state from the version because setting the
      // state can sometimes trigger additional state changes.
      const_cast<StateUpdater::TreeType&>(tree)[vertex].state = version->state;
    }
};

void StateUpdater::RecalculateStates() {
  // Possible optimization: Many assets have significant overlap in their
  // inputs. It might save time if we could calculate the overlapping state
  // only once.
  depth_first_search(tree, visitor(UpdateStateVisitor()));
}
<|endoftext|>


<commit_before>#include "model.h"
#include "view.h"
#include "controller.h"

int main()
{
	auto model = std::make_shared<Model>(58,58);
	auto view = std::make_unique<View>(model);
	auto controller = Controller::Create(model, std::move(view));

	controller->ShowView();

	return 0;
}<commit_msg>Leave grid size to default (50x50)<commit_after>#include "model.h"
#include "view.h"
#include "controller.h"

int main()
{
	auto model = std::make_shared<Model>();
	auto view = std::make_unique<View>(model);
	auto controller = Controller::Create(model, std::move(view));

	controller->ShowView();

	return 0;
}<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <limits.h>
#include <ctype.h>
#include <algorithm>

#include "base/file_util.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "net/base/sdch_filter.h"
#include "net/base/sdch_manager.h"

#include "sdch/open-vcdiff/src/google/vcdecoder.h"

SdchFilter::SdchFilter()
    : decoding_status_(DECODING_UNINITIALIZED),
      vcdiff_streaming_decoder_(NULL),
      dictionary_hash_(),
      dictionary_hash_is_plausible_(false),
      dictionary_(NULL),
      dest_buffer_excess_(),
      dest_buffer_excess_index_(0),
      source_bytes_(0),
      output_bytes_(0),
      possible_pass_through_(false) {
}

SdchFilter::~SdchFilter() {
  static int filter_use_count = 0;
  ++filter_use_count;
  if (META_REFRESH_RECOVERY == decoding_status_) {
    UMA_HISTOGRAM_COUNTS(L"Sdch.FilterUseBeforeDisabling", filter_use_count);
  }

  if (vcdiff_streaming_decoder_.get()) {
    if (!vcdiff_streaming_decoder_->FinishDecoding()) {
      decoding_status_ = DECODING_ERROR;
      SdchManager::SdchErrorRecovery(SdchManager::INCOMPLETE_SDCH_CONTENT);
      // Make it possible for the user to hit reload, and get non-sdch content.
      // Note this will "wear off" quickly enough, and is just meant to assure
      // in some rare case that the user is not stuck.
      SdchManager::BlacklistDomain(url());
    }
  }

  if (!was_cached()
      && base::Time() != connect_time()
      && read_times_.size() > 0
      && base::Time() != read_times_.back()) {
    base::TimeDelta duration = read_times_.back() - connect_time();
    // We clip our logging at 10 minutes to prevent anamolous data from being
    // considered (per suggestion from Jake Brutlag).
    if (10 >= duration.InMinutes()) {
      if (DECODING_IN_PROGRESS == decoding_status_) {
        UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Decode_Latency_F", duration,
                                    base::TimeDelta::FromMilliseconds(20),
                                    base::TimeDelta::FromMinutes(10), 100);
        UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Decode_1st_To_Last",
                                    read_times_.back() - read_times_[0],
                                    base::TimeDelta::FromMilliseconds(20),
                                    base::TimeDelta::FromMinutes(10), 100);
        if (read_times_.size() > 3)
          UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Decode_3rd_To_4th",
                                      read_times_[3] - read_times_[2],
                                      base::TimeDelta::FromMilliseconds(10),
                                      base::TimeDelta::FromSeconds(3), 100);
        UMA_HISTOGRAM_COUNTS_100(L"Sdch.Network_Decode_Reads",
                                 read_times_.size());
        UMA_HISTOGRAM_COUNTS(L"Sdch.Network_Decode_Bytes_Read", output_bytes_);
      } else if (PASS_THROUGH == decoding_status_) {
        UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Pass-through_Latency_F",
                                    duration,
                                    base::TimeDelta::FromMilliseconds(20),
                                    base::TimeDelta::FromMinutes(10), 100);
        UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Pass-through_1st_To_Last",
                                    read_times_.back() - read_times_[0],
                                    base::TimeDelta::FromMilliseconds(20),
                                    base::TimeDelta::FromMinutes(10), 100);
        if (read_times_.size() > 3)
          UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Pass-through_3rd_To_4th",
                                      read_times_[3] - read_times_[2],
                                      base::TimeDelta::FromMilliseconds(10),
                                      base::TimeDelta::FromSeconds(3), 100);
        UMA_HISTOGRAM_COUNTS_100(L"Sdch.Network_Pass-through_Reads",
                                 read_times_.size());
      }
    }
  }

  if (dictionary_)
    dictionary_->Release();
}

bool SdchFilter::InitDecoding(Filter::FilterType filter_type) {
  if (decoding_status_ != DECODING_UNINITIALIZED)
    return false;

  // Handle case  where sdch filter is guessed, but not required.
  if (FILTER_TYPE_SDCH_POSSIBLE == filter_type)
    possible_pass_through_ = true;

  // Initialize decoder only after we have a dictionary in hand.
  decoding_status_ = WAITING_FOR_DICTIONARY_SELECTION;
  return true;
}

static const char* kDecompressionErrorHtml =
  "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0\">"
  "
"
  "An error occurred. This page will be reloaded shortly. "
  "Or press the \"reload\" button now to reload it immediately."
  "
";

Filter::FilterStatus SdchFilter::ReadFilteredData(char* dest_buffer,
                                                  int* dest_len) {
  int available_space = *dest_len;
  *dest_len = 0;  // Nothing output yet.

  if (!dest_buffer || available_space <= 0)
    return FILTER_ERROR;

  // Don't update when we're called to just flush out our internal buffers.
  if (next_stream_data_ && stream_data_len_ > 0)
    read_times_.push_back(base::Time::Now());

  if (WAITING_FOR_DICTIONARY_SELECTION == decoding_status_) {
    FilterStatus status = InitializeDictionary();
    if (FILTER_NEED_MORE_DATA == status)
      return FILTER_NEED_MORE_DATA;
    if (FILTER_ERROR == status) {
      DCHECK(DECODING_ERROR == decoding_status_);
      DCHECK(0 == dest_buffer_excess_index_);
      DCHECK(dest_buffer_excess_.empty());
      if (possible_pass_through_) {
        // We added the sdch coding tag, and it should not have been added.
        // This can happen in server experiments, where the server decides
        // not to use sdch, even though there is a dictionary.  To be
        // conservative, we locally added the tentative sdch (fearing that a
        // proxy stripped it!) and we must now recant (pass through).
        SdchManager::SdchErrorRecovery(SdchManager::DISCARD_TENTATIVE_SDCH);
        decoding_status_ = PASS_THROUGH;
        dest_buffer_excess_ = dictionary_hash_;  // Send what we scanned.
      } else if (!dictionary_hash_is_plausible_) {
        // One of the first 9 bytes precluded consideration as a hash.
        // This can't be an SDCH payload, even though the server said it was.
        // This is a major error, as the server or proxy tagged this SDCH even
        // though it is not!
        // The good news is that error recovery is clear...
        SdchManager::SdchErrorRecovery(SdchManager::PASSING_THROUGH_NON_SDCH);
        decoding_status_ = PASS_THROUGH;
        dest_buffer_excess_ = dictionary_hash_;  // Send what we scanned.
      } else {
        // We don't have the dictionary that was demanded.
        // With very low probability, random garbage data looked like a
        // dictionary specifier (8 ASCII characters followed by a null), but
        // that is sufficiently unlikely that we ignore it.
        if (std::string::npos == mime_type().find_first_of("text/html")) {
          SdchManager::BlacklistDomainForever(url());
          if (was_cached_)
            SdchManager::SdchErrorRecovery(
                SdchManager::CACHED_META_REFRESH_UNSUPPORTED);
          else
            SdchManager::SdchErrorRecovery(
                SdchManager::META_REFRESH_UNSUPPORTED);
          return FILTER_ERROR;
        }
        // HTML content means we can issue a meta-refresh, and get the content
        // again, perhaps without SDCH (to be safe).
        if (was_cached_) {
          // Cached content is probably a startup tab, so we'll just get fresh
          // content and try again, without disabling sdch.
          SdchManager::SdchErrorRecovery(
              SdchManager::META_REFRESH_CACHED_RECOVERY);
        } else {
          // Since it wasn't in the cache, we definately need at least some
          // period of blacklisting to get the correct content.
          SdchManager::BlacklistDomain(url());
          SdchManager::SdchErrorRecovery(SdchManager::META_REFRESH_RECOVERY);
        }
        decoding_status_ = META_REFRESH_RECOVERY;
        // Issue a meta redirect with SDCH disabled.
        dest_buffer_excess_ = kDecompressionErrorHtml;
      }
    } else {
      DCHECK(DECODING_IN_PROGRESS == decoding_status_);
    }
  }

  int amount = OutputBufferExcess(dest_buffer, available_space);
  *dest_len += amount;
  dest_buffer += amount;
  available_space -= amount;
  DCHECK(available_space >= 0);

  if (available_space <= 0)
    return FILTER_OK;
  DCHECK(dest_buffer_excess_.empty());
  DCHECK(0 == dest_buffer_excess_index_);

  if (decoding_status_ != DECODING_IN_PROGRESS) {
    if (META_REFRESH_RECOVERY == decoding_status_) {
      // Absorb all input data.  We've already output page reload HTML.
      next_stream_data_ = NULL;
      stream_data_len_ = 0;
      return FILTER_NEED_MORE_DATA;
    }
    if (PASS_THROUGH == decoding_status_) {
      // We must pass in available_space, but it will be changed to bytes_used.
      FilterStatus result = CopyOut(dest_buffer, &available_space);
      // Accumulate the returned count of bytes_used (a.k.a., available_space).
      *dest_len += available_space;
      return result;
    }
    DCHECK(false);
    decoding_status_ = DECODING_ERROR;
    return FILTER_ERROR;
  }

  if (!next_stream_data_ || stream_data_len_ <= 0)
    return FILTER_NEED_MORE_DATA;

  bool ret = vcdiff_streaming_decoder_->DecodeChunk(
    next_stream_data_, stream_data_len_, &dest_buffer_excess_);
  // Assume all data was used in decoding.
  next_stream_data_ = NULL;
  source_bytes_ += stream_data_len_;
  stream_data_len_ = 0;
  output_bytes_ += dest_buffer_excess_.size();
  if (!ret) {
    vcdiff_streaming_decoder_.reset(NULL);  // Don't call it again.
    decoding_status_ = DECODING_ERROR;
    SdchManager::SdchErrorRecovery(SdchManager::DECODE_BODY_ERROR);
    return FILTER_ERROR;
  }

  amount = OutputBufferExcess(dest_buffer, available_space);
  *dest_len += amount;
  dest_buffer += amount;
  if (0 == available_space && !dest_buffer_excess_.empty())
      return FILTER_OK;
  return FILTER_NEED_MORE_DATA;
}

Filter::FilterStatus SdchFilter::InitializeDictionary() {
  const size_t kServerIdLength = 9;  // Dictionary hash plus null from server.
  size_t bytes_needed = kServerIdLength - dictionary_hash_.size();
  DCHECK(bytes_needed > 0);
  if (!next_stream_data_)
    return FILTER_NEED_MORE_DATA;
  if (static_cast<size_t>(stream_data_len_) < bytes_needed) {
    dictionary_hash_.append(next_stream_data_, stream_data_len_);
    next_stream_data_ = NULL;
    stream_data_len_ = 0;
    return FILTER_NEED_MORE_DATA;
  }
  dictionary_hash_.append(next_stream_data_, bytes_needed);
  DCHECK(kServerIdLength == dictionary_hash_.size());
  stream_data_len_ -= bytes_needed;
  DCHECK(0 <= stream_data_len_);
  if (stream_data_len_ > 0)
    next_stream_data_ += bytes_needed;
  else
    next_stream_data_ = NULL;

  DCHECK(!dictionary_);
  dictionary_hash_is_plausible_ = true;  // Assume plausible, but check.
  if ('\0' == dictionary_hash_[kServerIdLength - 1])
    SdchManager::Global()->GetVcdiffDictionary(std::string(dictionary_hash_, 0,
                                                           kServerIdLength - 1),
                                               url(), &dictionary_);
  else
    dictionary_hash_is_plausible_ = false;

  if (!dictionary_) {
    DCHECK(dictionary_hash_.size() == kServerIdLength);
    // Since dictionary was not found, check to see if hash was even plausible.
    for (size_t i = 0; i < kServerIdLength - 1; ++i) {
      char base64_char = dictionary_hash_[i];
      if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) {
        dictionary_hash_is_plausible_ = false;
        break;
      }
    }
    if (dictionary_hash_is_plausible_)
      SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_NOT_FOUND);
    else
      SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_MALFORMED);
    decoding_status_ = DECODING_ERROR;
    return FILTER_ERROR;
  }
  dictionary_->AddRef();
  vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
  vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(),
                                           dictionary_->text().size());
  decoding_status_ = DECODING_IN_PROGRESS;
  return FILTER_OK;
}

int SdchFilter::OutputBufferExcess(char* const dest_buffer,
                                   size_t available_space) {
  if (dest_buffer_excess_.empty())
    return 0;
  DCHECK(dest_buffer_excess_.size() > dest_buffer_excess_index_);
  size_t amount = std::min(available_space,
      dest_buffer_excess_.size() - dest_buffer_excess_index_);
  memcpy(dest_buffer, dest_buffer_excess_.data() + dest_buffer_excess_index_,
         amount);
  dest_buffer_excess_index_ += amount;
  if (dest_buffer_excess_.size() <= dest_buffer_excess_index_) {
    DCHECK(dest_buffer_excess_.size() == dest_buffer_excess_index_);
    dest_buffer_excess_.clear();
    dest_buffer_excess_index_ = 0;
  }
  return amount;
}
<commit_msg>Add one more histogram to SDCH decoder<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <limits.h>
#include <ctype.h>
#include <algorithm>

#include "base/file_util.h"
#include "base/histogram.h"
#include "base/logging.h"
#include "net/base/sdch_filter.h"
#include "net/base/sdch_manager.h"

#include "sdch/open-vcdiff/src/google/vcdecoder.h"

SdchFilter::SdchFilter()
    : decoding_status_(DECODING_UNINITIALIZED),
      vcdiff_streaming_decoder_(NULL),
      dictionary_hash_(),
      dictionary_hash_is_plausible_(false),
      dictionary_(NULL),
      dest_buffer_excess_(),
      dest_buffer_excess_index_(0),
      source_bytes_(0),
      output_bytes_(0),
      possible_pass_through_(false) {
}

SdchFilter::~SdchFilter() {
  static int filter_use_count = 0;
  ++filter_use_count;
  if (META_REFRESH_RECOVERY == decoding_status_) {
    UMA_HISTOGRAM_COUNTS(L"Sdch.FilterUseBeforeDisabling", filter_use_count);
  }

  if (vcdiff_streaming_decoder_.get()) {
    if (!vcdiff_streaming_decoder_->FinishDecoding()) {
      decoding_status_ = DECODING_ERROR;
      SdchManager::SdchErrorRecovery(SdchManager::INCOMPLETE_SDCH_CONTENT);
      // Make it possible for the user to hit reload, and get non-sdch content.
      // Note this will "wear off" quickly enough, and is just meant to assure
      // in some rare case that the user is not stuck.
      SdchManager::BlacklistDomain(url());
    }
  }

  if (!was_cached()
      && base::Time() != connect_time()
      && read_times_.size() > 0
      && base::Time() != read_times_.back()) {
    base::TimeDelta duration = read_times_.back() - connect_time();
    // We clip our logging at 10 minutes to prevent anamolous data from being
    // considered (per suggestion from Jake Brutlag).
    if (10 >= duration.InMinutes()) {
      if (DECODING_IN_PROGRESS == decoding_status_) {
        UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Decode_Latency_F", duration,
                                    base::TimeDelta::FromMilliseconds(20),
                                    base::TimeDelta::FromMinutes(10), 100);
        UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Decode_1st_To_Last",
                                    read_times_.back() - read_times_[0],
                                    base::TimeDelta::FromMilliseconds(20),
                                    base::TimeDelta::FromMinutes(10), 100);
        if (read_times_.size() > 3) {
          UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Decode_3rd_To_4th",
                                      read_times_[3] - read_times_[2],
                                      base::TimeDelta::FromMilliseconds(10),
                                      base::TimeDelta::FromSeconds(3), 100);
          UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Decode_2nd_To_3rd",
                                      read_times_[2] - read_times_[1],
                                      base::TimeDelta::FromMilliseconds(10),
                                      base::TimeDelta::FromSeconds(3), 100);
        }
        UMA_HISTOGRAM_COUNTS_100(L"Sdch.Network_Decode_Reads",
                                 read_times_.size());
        UMA_HISTOGRAM_COUNTS(L"Sdch.Network_Decode_Bytes_Read", output_bytes_);
      } else if (PASS_THROUGH == decoding_status_) {
        UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Pass-through_Latency_F",
                                    duration,
                                    base::TimeDelta::FromMilliseconds(20),
                                    base::TimeDelta::FromMinutes(10), 100);
        UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Pass-through_1st_To_Last",
                                    read_times_.back() - read_times_[0],
                                    base::TimeDelta::FromMilliseconds(20),
                                    base::TimeDelta::FromMinutes(10), 100);
        if (read_times_.size() > 3) {
          UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Pass-through_3rd_To_4th",
                                      read_times_[3] - read_times_[2],
                                      base::TimeDelta::FromMilliseconds(10),
                                      base::TimeDelta::FromSeconds(3), 100);
          UMA_HISTOGRAM_CLIPPED_TIMES(L"Sdch.Network_Pass-through_2nd_To_3rd",
                                      read_times_[2] - read_times_[1],
                                      base::TimeDelta::FromMilliseconds(10),
                                      base::TimeDelta::FromSeconds(3), 100);
        }
        UMA_HISTOGRAM_COUNTS_100(L"Sdch.Network_Pass-through_Reads",
                                 read_times_.size());
      }
    }
  }

  if (dictionary_)
    dictionary_->Release();
}

bool SdchFilter::InitDecoding(Filter::FilterType filter_type) {
  if (decoding_status_ != DECODING_UNINITIALIZED)
    return false;

  // Handle case  where sdch filter is guessed, but not required.
  if (FILTER_TYPE_SDCH_POSSIBLE == filter_type)
    possible_pass_through_ = true;

  // Initialize decoder only after we have a dictionary in hand.
  decoding_status_ = WAITING_FOR_DICTIONARY_SELECTION;
  return true;
}

static const char* kDecompressionErrorHtml =
  "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0\">"
  "
"
  "An error occurred. This page will be reloaded shortly. "
  "Or press the \"reload\" button now to reload it immediately."
  "
";

Filter::FilterStatus SdchFilter::ReadFilteredData(char* dest_buffer,
                                                  int* dest_len) {
  int available_space = *dest_len;
  *dest_len = 0;  // Nothing output yet.

  if (!dest_buffer || available_space <= 0)
    return FILTER_ERROR;

  // Don't update when we're called to just flush out our internal buffers.
  if (next_stream_data_ && stream_data_len_ > 0)
    read_times_.push_back(base::Time::Now());

  if (WAITING_FOR_DICTIONARY_SELECTION == decoding_status_) {
    FilterStatus status = InitializeDictionary();
    if (FILTER_NEED_MORE_DATA == status)
      return FILTER_NEED_MORE_DATA;
    if (FILTER_ERROR == status) {
      DCHECK(DECODING_ERROR == decoding_status_);
      DCHECK(0 == dest_buffer_excess_index_);
      DCHECK(dest_buffer_excess_.empty());
      if (possible_pass_through_) {
        // We added the sdch coding tag, and it should not have been added.
        // This can happen in server experiments, where the server decides
        // not to use sdch, even though there is a dictionary.  To be
        // conservative, we locally added the tentative sdch (fearing that a
        // proxy stripped it!) and we must now recant (pass through).
        SdchManager::SdchErrorRecovery(SdchManager::DISCARD_TENTATIVE_SDCH);
        decoding_status_ = PASS_THROUGH;
        dest_buffer_excess_ = dictionary_hash_;  // Send what we scanned.
      } else if (!dictionary_hash_is_plausible_) {
        // One of the first 9 bytes precluded consideration as a hash.
        // This can't be an SDCH payload, even though the server said it was.
        // This is a major error, as the server or proxy tagged this SDCH even
        // though it is not!
        // The good news is that error recovery is clear...
        SdchManager::SdchErrorRecovery(SdchManager::PASSING_THROUGH_NON_SDCH);
        decoding_status_ = PASS_THROUGH;
        dest_buffer_excess_ = dictionary_hash_;  // Send what we scanned.
      } else {
        // We don't have the dictionary that was demanded.
        // With very low probability, random garbage data looked like a
        // dictionary specifier (8 ASCII characters followed by a null), but
        // that is sufficiently unlikely that we ignore it.
        if (std::string::npos == mime_type().find_first_of("text/html")) {
          SdchManager::BlacklistDomainForever(url());
          if (was_cached_)
            SdchManager::SdchErrorRecovery(
                SdchManager::CACHED_META_REFRESH_UNSUPPORTED);
          else
            SdchManager::SdchErrorRecovery(
                SdchManager::META_REFRESH_UNSUPPORTED);
          return FILTER_ERROR;
        }
        // HTML content means we can issue a meta-refresh, and get the content
        // again, perhaps without SDCH (to be safe).
        if (was_cached_) {
          // Cached content is probably a startup tab, so we'll just get fresh
          // content and try again, without disabling sdch.
          SdchManager::SdchErrorRecovery(
              SdchManager::META_REFRESH_CACHED_RECOVERY);
        } else {
          // Since it wasn't in the cache, we definately need at least some
          // period of blacklisting to get the correct content.
          SdchManager::BlacklistDomain(url());
          SdchManager::SdchErrorRecovery(SdchManager::META_REFRESH_RECOVERY);
        }
        decoding_status_ = META_REFRESH_RECOVERY;
        // Issue a meta redirect with SDCH disabled.
        dest_buffer_excess_ = kDecompressionErrorHtml;
      }
    } else {
      DCHECK(DECODING_IN_PROGRESS == decoding_status_);
    }
  }

  int amount = OutputBufferExcess(dest_buffer, available_space);
  *dest_len += amount;
  dest_buffer += amount;
  available_space -= amount;
  DCHECK(available_space >= 0);

  if (available_space <= 0)
    return FILTER_OK;
  DCHECK(dest_buffer_excess_.empty());
  DCHECK(0 == dest_buffer_excess_index_);

  if (decoding_status_ != DECODING_IN_PROGRESS) {
    if (META_REFRESH_RECOVERY == decoding_status_) {
      // Absorb all input data.  We've already output page reload HTML.
      next_stream_data_ = NULL;
      stream_data_len_ = 0;
      return FILTER_NEED_MORE_DATA;
    }
    if (PASS_THROUGH == decoding_status_) {
      // We must pass in available_space, but it will be changed to bytes_used.
      FilterStatus result = CopyOut(dest_buffer, &available_space);
      // Accumulate the returned count of bytes_used (a.k.a., available_space).
      *dest_len += available_space;
      return result;
    }
    DCHECK(false);
    decoding_status_ = DECODING_ERROR;
    return FILTER_ERROR;
  }

  if (!next_stream_data_ || stream_data_len_ <= 0)
    return FILTER_NEED_MORE_DATA;

  bool ret = vcdiff_streaming_decoder_->DecodeChunk(
    next_stream_data_, stream_data_len_, &dest_buffer_excess_);
  // Assume all data was used in decoding.
  next_stream_data_ = NULL;
  source_bytes_ += stream_data_len_;
  stream_data_len_ = 0;
  output_bytes_ += dest_buffer_excess_.size();
  if (!ret) {
    vcdiff_streaming_decoder_.reset(NULL);  // Don't call it again.
    decoding_status_ = DECODING_ERROR;
    SdchManager::SdchErrorRecovery(SdchManager::DECODE_BODY_ERROR);
    return FILTER_ERROR;
  }

  amount = OutputBufferExcess(dest_buffer, available_space);
  *dest_len += amount;
  dest_buffer += amount;
  if (0 == available_space && !dest_buffer_excess_.empty())
      return FILTER_OK;
  return FILTER_NEED_MORE_DATA;
}

Filter::FilterStatus SdchFilter::InitializeDictionary() {
  const size_t kServerIdLength = 9;  // Dictionary hash plus null from server.
  size_t bytes_needed = kServerIdLength - dictionary_hash_.size();
  DCHECK(bytes_needed > 0);
  if (!next_stream_data_)
    return FILTER_NEED_MORE_DATA;
  if (static_cast<size_t>(stream_data_len_) < bytes_needed) {
    dictionary_hash_.append(next_stream_data_, stream_data_len_);
    next_stream_data_ = NULL;
    stream_data_len_ = 0;
    return FILTER_NEED_MORE_DATA;
  }
  dictionary_hash_.append(next_stream_data_, bytes_needed);
  DCHECK(kServerIdLength == dictionary_hash_.size());
  stream_data_len_ -= bytes_needed;
  DCHECK(0 <= stream_data_len_);
  if (stream_data_len_ > 0)
    next_stream_data_ += bytes_needed;
  else
    next_stream_data_ = NULL;

  DCHECK(!dictionary_);
  dictionary_hash_is_plausible_ = true;  // Assume plausible, but check.
  if ('\0' == dictionary_hash_[kServerIdLength - 1])
    SdchManager::Global()->GetVcdiffDictionary(std::string(dictionary_hash_, 0,
                                                           kServerIdLength - 1),
                                               url(), &dictionary_);
  else
    dictionary_hash_is_plausible_ = false;

  if (!dictionary_) {
    DCHECK(dictionary_hash_.size() == kServerIdLength);
    // Since dictionary was not found, check to see if hash was even plausible.
    for (size_t i = 0; i < kServerIdLength - 1; ++i) {
      char base64_char = dictionary_hash_[i];
      if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) {
        dictionary_hash_is_plausible_ = false;
        break;
      }
    }
    if (dictionary_hash_is_plausible_)
      SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_NOT_FOUND);
    else
      SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_MALFORMED);
    decoding_status_ = DECODING_ERROR;
    return FILTER_ERROR;
  }
  dictionary_->AddRef();
  vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
  vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(),
                                           dictionary_->text().size());
  decoding_status_ = DECODING_IN_PROGRESS;
  return FILTER_OK;
}

int SdchFilter::OutputBufferExcess(char* const dest_buffer,
                                   size_t available_space) {
  if (dest_buffer_excess_.empty())
    return 0;
  DCHECK(dest_buffer_excess_.size() > dest_buffer_excess_index_);
  size_t amount = std::min(available_space,
      dest_buffer_excess_.size() - dest_buffer_excess_index_);
  memcpy(dest_buffer, dest_buffer_excess_.data() + dest_buffer_excess_index_,
         amount);
  dest_buffer_excess_index_ += amount;
  if (dest_buffer_excess_.size() <= dest_buffer_excess_index_) {
    DCHECK(dest_buffer_excess_.size() == dest_buffer_excess_index_);
    dest_buffer_excess_.clear();
    dest_buffer_excess_index_ = 0;
  }
  return amount;
}
<|endoftext|>


<commit_before>#include "UDP.h"

#include "os.h"
#include "Endian.h"

#if defined( __POSIX__ )
	#include <arpa/inet.h>
    #include <sys/socket.h>
    #include <string.h>
#elif defined( __WIN_API__ )
	#include <WinSock2.h>
#endif

#if defined( __OS_X__ )
    #define INVALID_SOCKET  ( -1 )
#endif

#ifdef __WIN_API__
	typedef int socklen_t;
#endif

/*
====================
xiUDP::CreateOnPort

	Open a UDP socket on a given port
	This constructs the memory too
	If it fails, a nullptr is returned
	The port is automatically bound, so it is ready for both send and receive
====================
*/
xiUDP * xiUDP::CreateOnPort( const uint16_t port ) {
	xiUDP * const self = new xiUDP();

	if ( self->status == STATUS_INVALID ) {
		delete( self );

		return nullptr;
	}

	if ( !self->BindToPortV4( port ) ) {
		delete( self );

		return nullptr;
	}

	self->Grab();

	return self;
}

/*
====================
xiUDP::xiUDP

	Constructor
	Opens up a UDP socket
	Called internally
====================
*/
xiUDP::xiUDP() {
	status = STATUS_NOT_BOUND;
	nativeHandle = OpenNativeSocket( SOCK_DGRAM );

	if ( nativeHandle == INVALID_SOCKET ) {
		status = STATUS_INVALID;
	}
}

/*
====================
xiUDP::~xiUDP

	Deconstructor
	Protobase does the important destruction
====================
*/
xiUDP::~xiUDP() {
}

/*
====================
xiUDP::ReadIntoBuffer

	Read from the UDP socket into a given buffer
	senderInfo is not required, but would be needed for replying
	Returns the length of the received packet
====================
*/
byteLen_t xiUDP::ReadIntoBuffer( char * const buffer, const int32_t bufferLength, addressInfo_s * const senderInfo ) {
	sockaddr_in sender;
	socklen_t senderLength = ( socklen_t )sizeof( sender );

	const byteLen_t receivedBytes = recvfrom( nativeHandle, buffer, bufferLength, 0, ( sockaddr * )&sender, &senderLength );

	if ( senderInfo ) {
		memset( senderInfo, 0, sizeof( *senderInfo ) );

#ifdef __WIN_API__
		senderInfo->address.protocolV4[0] = sender.sin_addr.S_un.S_un_b.s_b1;
		senderInfo->address.protocolV4[1] = sender.sin_addr.S_un.S_un_b.s_b2;
		senderInfo->address.protocolV4[2] = sender.sin_addr.S_un.S_un_b.s_b3;
		senderInfo->address.protocolV4[3] = sender.sin_addr.S_un.S_un_b.s_b4;
#elif defined( __POSIX__ )
        memcpy( &senderInfo->address.protocolV4[0], &sender.sin_addr.s_addr, sizeof( sender.sin_addr.s_addr ) );
#endif

		senderInfo->port = ( uint16_t )Endian::NetworkToHostUnsigned( sender.sin_port, sizeof( sender.sin_port ) );
	}

	return receivedBytes;
}

/*
====================
xiUDP::SendBufferToAddress

	Fire-and-forget
	Sends a given buffer to the destination of targetInfo
	Nothing is done to check if it gets there
====================
*/
byteLen_t xiUDP::SendBufferToAddress( const char * const buffer, const int32_t bufferLength, const addressInfo_s targetInfo ) {
	sockaddr_in target;
	int targetLength = ( int )sizeof( target );
	memset( &target, 0, sizeof( target ) );

#ifdef __WIN_API__
	target.sin_family = AF_INET;
	target.sin_addr.S_un.S_un_b.s_b1 = targetInfo.address.protocolV4[0];
	target.sin_addr.S_un.S_un_b.s_b2 = targetInfo.address.protocolV4[1];
	target.sin_addr.S_un.S_un_b.s_b3 = targetInfo.address.protocolV4[2];
	target.sin_addr.S_un.S_un_b.s_b4 = targetInfo.address.protocolV4[3];
#elif defined( __POSIX__ )
    memcpy( &target.sin_addr.s_addr, &targetInfo.address.protocolV4[0], sizeof( target.sin_addr.s_addr ) );
#endif

	target.sin_port = ( uint16_t )Endian::HostToNetworkUnsigned( targetInfo.port, sizeof( targetInfo.port ) );

	const byteLen_t sentBytes = sendto( nativeHandle, buffer, bufferLength, 0, ( sockaddr * )&target, targetLength );

	return sentBytes;
}

/*
====================
xiUDP::BroadcastBuffer

	Broadcasts a given buffer on the same subnet that the socket is bound
	The port is the "destination" port of all the potential receivers of the packet
	The broadcastAllowed boolean must be set for this method to work
====================
*/
byteLen_t xiUDP::BroadcastBuffer( const char * const buffer, const int32_t bufferLength, const uint16_t port ) {
	if ( broadcastAllowed == false ) {
		// Broadcasting not allowed!
		return 0;
	}

	sockaddr_in target;
	int targetLength = ( int )sizeof( target );
	memset( &target, 0, sizeof( target ) );

#ifdef __WIN_API__
	target.sin_family = AF_INET;
	target.sin_addr.s_addr = INADDR_BROADCAST;
#elif defined( __POSIX__ )
    //memcpy( &target.sin_addr.s_addr, &targetInfo.address.protocolV4[0], sizeof( target.sin_addr.s_addr ) );
#endif

	target.sin_port = ( uint16_t )Endian::HostToNetworkUnsigned( port, sizeof( port ) );

	const byteLen_t sentBytes = sendto( nativeHandle, buffer, bufferLength, 0, ( sockaddr * )&target, targetLength );

	return sentBytes;
}<commit_msg>Enabled UDP broadcasting for POSIX<commit_after>#include "UDP.h"

#include "os.h"
#include "Endian.h"

#if defined( __POSIX__ )
	#include <arpa/inet.h>
    #include <sys/socket.h>
    #include <string.h>
#elif defined( __WIN_API__ )
	#include <WinSock2.h>
#endif

#if defined( __OS_X__ )
    #define INVALID_SOCKET  ( -1 )
#endif

#ifdef __WIN_API__
	typedef int socklen_t;
#endif

/*
====================
xiUDP::CreateOnPort

	Open a UDP socket on a given port
	This constructs the memory too
	If it fails, a nullptr is returned
	The port is automatically bound, so it is ready for both send and receive
====================
*/
xiUDP * xiUDP::CreateOnPort( const uint16_t port ) {
	xiUDP * const self = new xiUDP();

	if ( self->status == STATUS_INVALID ) {
		delete( self );

		return nullptr;
	}

	if ( !self->BindToPortV4( port ) ) {
		delete( self );

		return nullptr;
	}

	self->Grab();

	return self;
}

/*
====================
xiUDP::xiUDP

	Constructor
	Opens up a UDP socket
	Called internally
====================
*/
xiUDP::xiUDP() {
	status = STATUS_NOT_BOUND;
	nativeHandle = OpenNativeSocket( SOCK_DGRAM );

	if ( nativeHandle == INVALID_SOCKET ) {
		status = STATUS_INVALID;
	}
}

/*
====================
xiUDP::~xiUDP

	Deconstructor
	Protobase does the important destruction
====================
*/
xiUDP::~xiUDP() {
}

/*
====================
xiUDP::ReadIntoBuffer

	Read from the UDP socket into a given buffer
	senderInfo is not required, but would be needed for replying
	Returns the length of the received packet
====================
*/
byteLen_t xiUDP::ReadIntoBuffer( char * const buffer, const int32_t bufferLength, addressInfo_s * const senderInfo ) {
	sockaddr_in sender;
	socklen_t senderLength = ( socklen_t )sizeof( sender );

	const byteLen_t receivedBytes = recvfrom( nativeHandle, buffer, bufferLength, 0, ( sockaddr * )&sender, &senderLength );

	if ( senderInfo ) {
		memset( senderInfo, 0, sizeof( *senderInfo ) );

#ifdef __WIN_API__
		senderInfo->address.protocolV4[0] = sender.sin_addr.S_un.S_un_b.s_b1;
		senderInfo->address.protocolV4[1] = sender.sin_addr.S_un.S_un_b.s_b2;
		senderInfo->address.protocolV4[2] = sender.sin_addr.S_un.S_un_b.s_b3;
		senderInfo->address.protocolV4[3] = sender.sin_addr.S_un.S_un_b.s_b4;
#elif defined( __POSIX__ )
        memcpy( &senderInfo->address.protocolV4[0], &sender.sin_addr.s_addr, sizeof( sender.sin_addr.s_addr ) );
#endif

		senderInfo->port = ( uint16_t )Endian::NetworkToHostUnsigned( sender.sin_port, sizeof( sender.sin_port ) );
	}

	return receivedBytes;
}

/*
====================
xiUDP::SendBufferToAddress

	Fire-and-forget
	Sends a given buffer to the destination of targetInfo
	Nothing is done to check if it gets there
====================
*/
byteLen_t xiUDP::SendBufferToAddress( const char * const buffer, const int32_t bufferLength, const addressInfo_s targetInfo ) {
	sockaddr_in target;
	int targetLength = ( int )sizeof( target );
	memset( &target, 0, sizeof( target ) );

#ifdef __WIN_API__
	target.sin_family = AF_INET;
	target.sin_addr.S_un.S_un_b.s_b1 = targetInfo.address.protocolV4[0];
	target.sin_addr.S_un.S_un_b.s_b2 = targetInfo.address.protocolV4[1];
	target.sin_addr.S_un.S_un_b.s_b3 = targetInfo.address.protocolV4[2];
	target.sin_addr.S_un.S_un_b.s_b4 = targetInfo.address.protocolV4[3];
#elif defined( __POSIX__ )
    memcpy( &target.sin_addr.s_addr, &targetInfo.address.protocolV4[0], sizeof( target.sin_addr.s_addr ) );
#endif

	target.sin_port = ( uint16_t )Endian::HostToNetworkUnsigned( targetInfo.port, sizeof( targetInfo.port ) );

	const byteLen_t sentBytes = sendto( nativeHandle, buffer, bufferLength, 0, ( sockaddr * )&target, targetLength );

	return sentBytes;
}

/*
====================
xiUDP::BroadcastBuffer

	Broadcasts a given buffer on the same subnet that the socket is bound
	The port is the "destination" port of all the potential receivers of the packet
	The broadcastAllowed boolean must be set for this method to work
====================
*/
byteLen_t xiUDP::BroadcastBuffer( const char * const buffer, const int32_t bufferLength, const uint16_t port ) {
	if ( broadcastAllowed == false ) {
		// Broadcasting not allowed!
		return 0;
	}

	sockaddr_in target;
	int targetLength = ( int )sizeof( target );
	memset( &target, 0, sizeof( target ) );

    target.sin_family = AF_INET;
    target.sin_addr.s_addr = INADDR_BROADCAST;

	target.sin_port = ( uint16_t )Endian::HostToNetworkUnsigned( port, sizeof( port ) );

	const byteLen_t sentBytes = sendto( nativeHandle, buffer, bufferLength, 0, ( sockaddr * )&target, targetLength );

	return sentBytes;
}<|endoftext|>