<commit_before>#ifndef DUNE_GDT_ASSEMBLER_WRAPPER_HH
#define DUNE_GDT_ASSEMBLER_WRAPPER_HH

#include <type_traits>

#include <dune/stuff/common/tmp-storage.hh>
#include <dune/stuff/la/container/interfaces.hh>
#include <dune/stuff/grid/walker.hh>
#include <dune/stuff/grid/walker/apply-on.hh>
#include <dune/stuff/grid/walker/functors.hh>
#include <dune/stuff/grid/walker/wrapper.hh>

#include <dune/gdt/spaces/interface.hh>
#include <dune/gdt/spaces/constraints.hh>

#include "local/codim0.hh"
#include "local/codim1.hh"
#include "tmp-storage.hh"

namespace Dune {
namespace GDT {
namespace internal {

template <class TestSpaceType, class AnsatzSpaceType, class GridViewType, class ConstraintsType>
class ConstraintsWrapper : public Stuff::Grid::internal::Codim0Object<GridViewType>
{
  static_assert(AlwaysFalse<ConstraintsType>::value, "Please add a specialization for these Constraints!");
};

template <class TestSpaceType, class AnsatzSpaceType, class GridViewType>
class ConstraintsWrapper<TestSpaceType, AnsatzSpaceType, GridViewType,
                         Spaces::DirichletConstraints<typename GridViewType::Intersection>>
    : public Stuff::Grid::internal::Codim0Object<GridViewType>
{
  static_assert(is_space<TestSpaceType>::value, "TestSpaceType has to be derived from SpaceInterface!");
  static_assert(is_space<AnsatzSpaceType>::value, "AnsatzSpaceType has to be derived from SpaceInterface!");
  typedef Stuff::Grid::internal::Codim0Object<GridViewType> BaseType;
  typedef Spaces::DirichletConstraints<typename GridViewType::Intersection> ConstraintsType;

public:
  typedef typename BaseType::EntityType EntityType;

  ConstraintsWrapper(const DS::PerThreadValue<const TestSpaceType>& test_space,
                     const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space,
                     const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>* where, ConstraintsType& constraints)
    : test_space_(test_space)
    , ansatz_space_(ansatz_space)
    , where_(where)
    , constraints_(constraints)
    , thread_local_constraints_(constraints_.boundary_info(), constraints_.size())
  {
  }

  virtual ~ConstraintsWrapper()
  {
  }

  virtual bool apply_on(const GridViewType& gv, const EntityType& entity) const override final
  {
    return where_->apply_on(gv, entity);
  }

  virtual void apply_local(const EntityType& entity) override final
  {
    test_space_->local_constraints(*ansatz_space_, entity, *thread_local_constraints_);
  }

  virtual void finalize() override final
  {
    std::lock_guard<std::mutex> DUNE_UNUSED(mutex_guard)(constraints_.mutex_);
    constraints_.dirichlet_DoFs_.insert(thread_local_constraints_->dirichlet_DoFs_.begin(),
                                        thread_local_constraints_->dirichlet_DoFs_.end());
  }

private:
  const DS::PerThreadValue<const TestSpaceType>& test_space_;
  const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space_;
  const std::unique_ptr<const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>> where_;
  ConstraintsType& constraints_;
  DS::PerThreadValue<ConstraintsType> thread_local_constraints_;
}; // class ConstraintsWrapper

template <class AssemblerType, class LocalVolumeMatrixAssembler, class MatrixType>
class LocalVolumeMatrixAssemblerWrapper
    : public Stuff::Grid::internal::Codim0Object<typename AssemblerType::GridViewType>,
      DSC::TmpMatricesStorage<typename AssemblerType::TestSpaceType::RangeFieldType>
{
  typedef DSC::TmpMatricesStorage<typename AssemblerType::TestSpaceType::RangeFieldType> TmpMatricesProvider;

public:
  typedef typename AssemblerType::TestSpaceType TestSpaceType;
  typedef typename AssemblerType::AnsatzSpaceType AnsatzSpaceType;
  typedef typename AssemblerType::GridViewType GridViewType;
  typedef typename AssemblerType::EntityType EntityType;

  LocalVolumeMatrixAssemblerWrapper(const DS::PerThreadValue<const TestSpaceType>& test_space,
                                    const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space,
                                    const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>* where,
                                    const LocalVolumeMatrixAssembler& localAssembler, MatrixType& matrix)
    : TmpMatricesProvider(localAssembler.numTmpObjectsRequired(), test_space->mapper().maxNumDofs(),
                          ansatz_space->mapper().maxNumDofs())
    , test_space_(test_space)
    , ansatz_space_(ansatz_space)
    , where_(where)
    , localMatrixAssembler_(localAssembler)
    , matrix_(matrix)
  {
  }

  virtual ~LocalVolumeMatrixAssemblerWrapper()
  {
  }

  virtual bool apply_on(const GridViewType& gv, const EntityType& entity) const override final
  {
    return where_->apply_on(gv, entity);
  }

  virtual void apply_local(const EntityType& entity) override final
  {
    localMatrixAssembler_.assembleLocal(
        *test_space_, *ansatz_space_, entity, matrix_, this->matrices(), this->indices());
  }

private:
  const DS::PerThreadValue<const TestSpaceType>& test_space_;
  const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space_;
  const std::unique_ptr<const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>> where_;
  const LocalVolumeMatrixAssembler& localMatrixAssembler_;
  MatrixType& matrix_;
}; // class LocalVolumeMatrixAssemblerWrapper

template <class AssemblerType, class LocalFaceMatrixAssembler, class MatrixType>
class LocalFaceMatrixAssemblerWrapper
    : public Stuff::Grid::internal::Codim1Object<typename AssemblerType::GridViewType>,
      DSC::TmpMatricesStorage<typename AssemblerType::TestSpaceType::RangeFieldType>
{
  typedef DSC::TmpMatricesStorage<typename AssemblerType::TestSpaceType::RangeFieldType> TmpMatricesProvider;

public:
  typedef typename AssemblerType::TestSpaceType TestSpaceType;
  typedef typename AssemblerType::AnsatzSpaceType AnsatzSpaceType;
  typedef typename AssemblerType::GridViewType GridViewType;
  typedef typename AssemblerType::EntityType EntityType;
  typedef typename Stuff::Grid::internal::Codim1Object<GridViewType>::IntersectionType IntersectionType;

  LocalFaceMatrixAssemblerWrapper(const DS::PerThreadValue<const TestSpaceType>& test_space,
                                  const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space,
                                  const Stuff::Grid::ApplyOn::WhichIntersection<GridViewType>* where,
                                  const LocalFaceMatrixAssembler& localAssembler, MatrixType& matrix)
    : TmpMatricesProvider(localAssembler.numTmpObjectsRequired(), test_space->mapper().maxNumDofs(),
                          ansatz_space->mapper().maxNumDofs())
    , test_space_(test_space)
    , ansatz_space_(ansatz_space)
    , where_(where)
    , localMatrixAssembler_(localAssembler)
    , matrix_(matrix)
  {
  }

  virtual ~LocalFaceMatrixAssemblerWrapper()
  {
  }

  virtual bool apply_on(const GridViewType& gv, const IntersectionType& intersection) const override final
  {
    return where_->apply_on(gv, intersection);
  }

  virtual void apply_local(const IntersectionType& intersection, const EntityType& /*inside_entity*/,
                           const EntityType& /*outside_entity*/) override final
  {
    localMatrixAssembler_.assembleLocal(
        *test_space_, *ansatz_space_, intersection, matrix_, this->matrices(), this->indices());
  } // ... apply_local(...)

private:
  const DS::PerThreadValue<const TestSpaceType>& test_space_;
  const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space_;
  const std::unique_ptr<const Stuff::Grid::ApplyOn::WhichIntersection<GridViewType>> where_;
  const LocalFaceMatrixAssembler& localMatrixAssembler_;
  MatrixType& matrix_;
}; // class LocalFaceMatrixAssemblerWrapper

template <class AssemblerType, class LocalVolumeVectorAssembler, class VectorType>
class LocalVolumeVectorAssemblerWrapper
    : public Stuff::Grid::internal::Codim0Object<typename AssemblerType::GridViewType>,
      DSC::TmpVectorsStorage<typename AssemblerType::TestSpaceType::RangeFieldType>
{
  typedef DSC::TmpVectorsStorage<typename AssemblerType::TestSpaceType::RangeFieldType> TmpVectorsProvider;

public:
  typedef typename AssemblerType::TestSpaceType TestSpaceType;
  typedef typename AssemblerType::GridViewType GridViewType;
  typedef typename AssemblerType::EntityType EntityType;

  LocalVolumeVectorAssemblerWrapper(const DS::PerThreadValue<const TestSpaceType>& space,
                                    const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>* where,
                                    const LocalVolumeVectorAssembler& localAssembler, VectorType& vector)
    : TmpVectorsProvider(localAssembler.numTmpObjectsRequired(), space->mapper().maxNumDofs())
    , space_(space)
    , where_(where)
    , localVectorAssembler_(localAssembler)
    , vector_(vector)
  {
  }

  virtual ~LocalVolumeVectorAssemblerWrapper()
  {
  }

  virtual bool apply_on(const GridViewType& gv, const EntityType& entity) const override final
  {
    return where_->apply_on(gv, entity);
  }

  virtual void apply_local(const EntityType& entity) override final
  {
    localVectorAssembler_.assembleLocal(*space_, entity, vector_, this->vectors(), this->indices());
  }

private:
  const DS::PerThreadValue<const TestSpaceType>& space_;
  const std::unique_ptr<const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>> where_;
  const LocalVolumeVectorAssembler& localVectorAssembler_;
  VectorType& vector_;
}; // class LocalVolumeVectorAssemblerWrapper

template <class AssemblerType, class LocalFaceVectorAssembler, class VectorType>
class LocalFaceVectorAssemblerWrapper
    : public Stuff::Grid::internal::Codim1Object<typename AssemblerType::GridViewType>,
      DSC::TmpVectorsStorage<typename AssemblerType::TestSpaceType::RangeFieldType>
{
  typedef DSC::TmpVectorsStorage<typename AssemblerType::TestSpaceType::RangeFieldType> TmpVectorsProvider;

public:
  typedef typename AssemblerType::TestSpaceType TestSpaceType;
  typedef typename AssemblerType::GridViewType GridViewType;
  typedef typename AssemblerType::EntityType EntityType;
  typedef typename Stuff::Grid::internal::Codim1Object<GridViewType>::IntersectionType IntersectionType;

  LocalFaceVectorAssemblerWrapper(const DS::PerThreadValue<const TestSpaceType>& space,
                                  const Stuff::Grid::ApplyOn::WhichIntersection<GridViewType>* where,
                                  const LocalFaceVectorAssembler& localAssembler, VectorType& vector)
    : TmpVectorsProvider(localAssembler.numTmpObjectsRequired(), space->mapper().maxNumDofs())
    , space_(space)
    , where_(where)
    , localVectorAssembler_(localAssembler)
    , vector_(vector)
  {
  }

  virtual ~LocalFaceVectorAssemblerWrapper()
  {
  }

  virtual bool apply_on(const GridViewType& gv, const IntersectionType& intersection) const override final
  {
    return where_->apply_on(gv, intersection);
  }

  virtual void apply_local(const IntersectionType& intersection, const EntityType& /*inside_entity*/,
                           const EntityType& /*outside_entity*/) override final
  {
    localVectorAssembler_.assembleLocal(*space_, intersection, vector_, this->vectors(), this->indices());
  }

private:
  const DS::PerThreadValue<const TestSpaceType>& space_;
  const std::unique_ptr<const Stuff::Grid::ApplyOn::WhichIntersection<GridViewType>> where_;
  const LocalFaceVectorAssembler& localVectorAssembler_;
  VectorType& vector_;
}; // class LocalFaceVectorAssemblerWrapper

} // namespace internal
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_ASSEMBLER_WRAPPER_HH
<commit_msg>[assembler.wrapper] add LocalVolumeTwoFormWrapper<commit_after>#ifndef DUNE_GDT_ASSEMBLER_WRAPPER_HH
#define DUNE_GDT_ASSEMBLER_WRAPPER_HH

#include <type_traits>

#include <dune/stuff/common/tmp-storage.hh>
#include <dune/stuff/la/container/interfaces.hh>
#include <dune/stuff/grid/walker.hh>
#include <dune/stuff/grid/walker/apply-on.hh>
#include <dune/stuff/grid/walker/functors.hh>
#include <dune/stuff/grid/walker/wrapper.hh>

#include <dune/gdt/spaces/interface.hh>
#include <dune/gdt/spaces/constraints.hh>

#include "local/codim0.hh"
#include "local/codim1.hh"
#include "tmp-storage.hh"

namespace Dune {
namespace GDT {
namespace internal {

template <class TestSpaceType, class AnsatzSpaceType, class GridViewType, class ConstraintsType>
class ConstraintsWrapper : public Stuff::Grid::internal::Codim0Object<GridViewType>
{
  static_assert(AlwaysFalse<ConstraintsType>::value, "Please add a specialization for these Constraints!");
};

template <class TestSpaceType, class AnsatzSpaceType, class GridViewType>
class ConstraintsWrapper<TestSpaceType, AnsatzSpaceType, GridViewType,
                         Spaces::DirichletConstraints<typename GridViewType::Intersection>>
    : public Stuff::Grid::internal::Codim0Object<GridViewType>
{
  static_assert(is_space<TestSpaceType>::value, "TestSpaceType has to be derived from SpaceInterface!");
  static_assert(is_space<AnsatzSpaceType>::value, "AnsatzSpaceType has to be derived from SpaceInterface!");
  typedef Stuff::Grid::internal::Codim0Object<GridViewType> BaseType;
  typedef Spaces::DirichletConstraints<typename GridViewType::Intersection> ConstraintsType;

public:
  typedef typename BaseType::EntityType EntityType;

  ConstraintsWrapper(const DS::PerThreadValue<const TestSpaceType>& test_space,
                     const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space,
                     const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>* where, ConstraintsType& constraints)
    : test_space_(test_space)
    , ansatz_space_(ansatz_space)
    , where_(where)
    , constraints_(constraints)
    , thread_local_constraints_(constraints_.boundary_info(), constraints_.size())
  {
  }

  virtual ~ConstraintsWrapper()
  {
  }

  virtual bool apply_on(const GridViewType& gv, const EntityType& entity) const override final
  {
    return where_->apply_on(gv, entity);
  }

  virtual void apply_local(const EntityType& entity) override final
  {
    test_space_->local_constraints(*ansatz_space_, entity, *thread_local_constraints_);
  }

  virtual void finalize() override final
  {
    std::lock_guard<std::mutex> DUNE_UNUSED(mutex_guard)(constraints_.mutex_);
    constraints_.dirichlet_DoFs_.insert(thread_local_constraints_->dirichlet_DoFs_.begin(),
                                        thread_local_constraints_->dirichlet_DoFs_.end());
  }

private:
  const DS::PerThreadValue<const TestSpaceType>& test_space_;
  const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space_;
  const std::unique_ptr<const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>> where_;
  ConstraintsType& constraints_;
  DS::PerThreadValue<ConstraintsType> thread_local_constraints_;
}; // class ConstraintsWrapper

template <class AssemblerType, class LocalTwoFormType, class MatrixType>
class LocalVolumeTwoFormWrapper : public Stuff::Grid::internal::Codim0Object<typename AssemblerType::GridViewType>
{
public:
  typedef typename AssemblerType::TestSpaceType TestSpaceType;
  typedef typename AssemblerType::AnsatzSpaceType AnsatzSpaceType;
  typedef typename AssemblerType::GridViewType GridViewType;
  typedef typename AssemblerType::EntityType EntityType;

  LocalVolumeTwoFormWrapper(const DS::PerThreadValue<const TestSpaceType>& test_space,
                            const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space,
                            const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>* where,
                            const LocalTwoFormType& local_twoform, MatrixType& matrix)
    : test_space_(test_space)
    , ansatz_space_(ansatz_space)
    , where_(where)
    , local_twoform_(local_twoform)
    , matrix_(matrix)
    , local_assembler_(local_twoform_)
  {
  }

  virtual ~LocalVolumeTwoFormWrapper() = default;

  virtual bool apply_on(const GridViewType& gv, const EntityType& entity) const override final
  {
    return where_->apply_on(gv, entity);
  }

  virtual void apply_local(const EntityType& entity) override final
  {
    local_assembler_.assemble(*test_space_, *ansatz_space_, entity, matrix_);
  }

private:
  const DS::PerThreadValue<const TestSpaceType>& test_space_;
  const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space_;
  const std::unique_ptr<const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>> where_;
  const LocalTwoFormType& local_twoform_;
  MatrixType& matrix_;
  const LocalVolumeTwoFormAssembler<LocalTwoFormType> local_assembler_;
}; // class LocalVolumeTwoFormWrapper

template <class AssemblerType, class LocalVolumeMatrixAssembler, class MatrixType>
class LocalVolumeMatrixAssemblerWrapper
    : public Stuff::Grid::internal::Codim0Object<typename AssemblerType::GridViewType>,
      DSC::TmpMatricesStorage<typename AssemblerType::TestSpaceType::RangeFieldType>
{
  typedef DSC::TmpMatricesStorage<typename AssemblerType::TestSpaceType::RangeFieldType> TmpMatricesProvider;

public:
  typedef typename AssemblerType::TestSpaceType TestSpaceType;
  typedef typename AssemblerType::AnsatzSpaceType AnsatzSpaceType;
  typedef typename AssemblerType::GridViewType GridViewType;
  typedef typename AssemblerType::EntityType EntityType;

  LocalVolumeMatrixAssemblerWrapper(const DS::PerThreadValue<const TestSpaceType>& test_space,
                                    const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space,
                                    const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>* where,
                                    const LocalVolumeMatrixAssembler& localAssembler, MatrixType& matrix)
    : TmpMatricesProvider(localAssembler.numTmpObjectsRequired(), test_space->mapper().maxNumDofs(),
                          ansatz_space->mapper().maxNumDofs())
    , test_space_(test_space)
    , ansatz_space_(ansatz_space)
    , where_(where)
    , localMatrixAssembler_(localAssembler)
    , matrix_(matrix)
  {
  }

  virtual ~LocalVolumeMatrixAssemblerWrapper()
  {
  }

  virtual bool apply_on(const GridViewType& gv, const EntityType& entity) const override final
  {
    return where_->apply_on(gv, entity);
  }

  virtual void apply_local(const EntityType& entity) override final
  {
    localMatrixAssembler_.assembleLocal(
        *test_space_, *ansatz_space_, entity, matrix_, this->matrices(), this->indices());
  }

private:
  const DS::PerThreadValue<const TestSpaceType>& test_space_;
  const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space_;
  const std::unique_ptr<const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>> where_;
  const LocalVolumeMatrixAssembler& localMatrixAssembler_;
  MatrixType& matrix_;
}; // class LocalVolumeMatrixAssemblerWrapper

template <class AssemblerType, class LocalFaceMatrixAssembler, class MatrixType>
class LocalFaceMatrixAssemblerWrapper
    : public Stuff::Grid::internal::Codim1Object<typename AssemblerType::GridViewType>,
      DSC::TmpMatricesStorage<typename AssemblerType::TestSpaceType::RangeFieldType>
{
  typedef DSC::TmpMatricesStorage<typename AssemblerType::TestSpaceType::RangeFieldType> TmpMatricesProvider;

public:
  typedef typename AssemblerType::TestSpaceType TestSpaceType;
  typedef typename AssemblerType::AnsatzSpaceType AnsatzSpaceType;
  typedef typename AssemblerType::GridViewType GridViewType;
  typedef typename AssemblerType::EntityType EntityType;
  typedef typename Stuff::Grid::internal::Codim1Object<GridViewType>::IntersectionType IntersectionType;

  LocalFaceMatrixAssemblerWrapper(const DS::PerThreadValue<const TestSpaceType>& test_space,
                                  const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space,
                                  const Stuff::Grid::ApplyOn::WhichIntersection<GridViewType>* where,
                                  const LocalFaceMatrixAssembler& localAssembler, MatrixType& matrix)
    : TmpMatricesProvider(localAssembler.numTmpObjectsRequired(), test_space->mapper().maxNumDofs(),
                          ansatz_space->mapper().maxNumDofs())
    , test_space_(test_space)
    , ansatz_space_(ansatz_space)
    , where_(where)
    , localMatrixAssembler_(localAssembler)
    , matrix_(matrix)
  {
  }

  virtual ~LocalFaceMatrixAssemblerWrapper()
  {
  }

  virtual bool apply_on(const GridViewType& gv, const IntersectionType& intersection) const override final
  {
    return where_->apply_on(gv, intersection);
  }

  virtual void apply_local(const IntersectionType& intersection, const EntityType& /*inside_entity*/,
                           const EntityType& /*outside_entity*/) override final
  {
    localMatrixAssembler_.assembleLocal(
        *test_space_, *ansatz_space_, intersection, matrix_, this->matrices(), this->indices());
  } // ... apply_local(...)

private:
  const DS::PerThreadValue<const TestSpaceType>& test_space_;
  const DS::PerThreadValue<const AnsatzSpaceType>& ansatz_space_;
  const std::unique_ptr<const Stuff::Grid::ApplyOn::WhichIntersection<GridViewType>> where_;
  const LocalFaceMatrixAssembler& localMatrixAssembler_;
  MatrixType& matrix_;
}; // class LocalFaceMatrixAssemblerWrapper

template <class AssemblerType, class LocalVolumeVectorAssembler, class VectorType>
class LocalVolumeVectorAssemblerWrapper
    : public Stuff::Grid::internal::Codim0Object<typename AssemblerType::GridViewType>,
      DSC::TmpVectorsStorage<typename AssemblerType::TestSpaceType::RangeFieldType>
{
  typedef DSC::TmpVectorsStorage<typename AssemblerType::TestSpaceType::RangeFieldType> TmpVectorsProvider;

public:
  typedef typename AssemblerType::TestSpaceType TestSpaceType;
  typedef typename AssemblerType::GridViewType GridViewType;
  typedef typename AssemblerType::EntityType EntityType;

  LocalVolumeVectorAssemblerWrapper(const DS::PerThreadValue<const TestSpaceType>& space,
                                    const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>* where,
                                    const LocalVolumeVectorAssembler& localAssembler, VectorType& vector)
    : TmpVectorsProvider(localAssembler.numTmpObjectsRequired(), space->mapper().maxNumDofs())
    , space_(space)
    , where_(where)
    , localVectorAssembler_(localAssembler)
    , vector_(vector)
  {
  }

  virtual ~LocalVolumeVectorAssemblerWrapper()
  {
  }

  virtual bool apply_on(const GridViewType& gv, const EntityType& entity) const override final
  {
    return where_->apply_on(gv, entity);
  }

  virtual void apply_local(const EntityType& entity) override final
  {
    localVectorAssembler_.assembleLocal(*space_, entity, vector_, this->vectors(), this->indices());
  }

private:
  const DS::PerThreadValue<const TestSpaceType>& space_;
  const std::unique_ptr<const Stuff::Grid::ApplyOn::WhichEntity<GridViewType>> where_;
  const LocalVolumeVectorAssembler& localVectorAssembler_;
  VectorType& vector_;
}; // class LocalVolumeVectorAssemblerWrapper

template <class AssemblerType, class LocalFaceVectorAssembler, class VectorType>
class LocalFaceVectorAssemblerWrapper
    : public Stuff::Grid::internal::Codim1Object<typename AssemblerType::GridViewType>,
      DSC::TmpVectorsStorage<typename AssemblerType::TestSpaceType::RangeFieldType>
{
  typedef DSC::TmpVectorsStorage<typename AssemblerType::TestSpaceType::RangeFieldType> TmpVectorsProvider;

public:
  typedef typename AssemblerType::TestSpaceType TestSpaceType;
  typedef typename AssemblerType::GridViewType GridViewType;
  typedef typename AssemblerType::EntityType EntityType;
  typedef typename Stuff::Grid::internal::Codim1Object<GridViewType>::IntersectionType IntersectionType;

  LocalFaceVectorAssemblerWrapper(const DS::PerThreadValue<const TestSpaceType>& space,
                                  const Stuff::Grid::ApplyOn::WhichIntersection<GridViewType>* where,
                                  const LocalFaceVectorAssembler& localAssembler, VectorType& vector)
    : TmpVectorsProvider(localAssembler.numTmpObjectsRequired(), space->mapper().maxNumDofs())
    , space_(space)
    , where_(where)
    , localVectorAssembler_(localAssembler)
    , vector_(vector)
  {
  }

  virtual ~LocalFaceVectorAssemblerWrapper()
  {
  }

  virtual bool apply_on(const GridViewType& gv, const IntersectionType& intersection) const override final
  {
    return where_->apply_on(gv, intersection);
  }

  virtual void apply_local(const IntersectionType& intersection, const EntityType& /*inside_entity*/,
                           const EntityType& /*outside_entity*/) override final
  {
    localVectorAssembler_.assembleLocal(*space_, intersection, vector_, this->vectors(), this->indices());
  }

private:
  const DS::PerThreadValue<const TestSpaceType>& space_;
  const std::unique_ptr<const Stuff::Grid::ApplyOn::WhichIntersection<GridViewType>> where_;
  const LocalFaceVectorAssembler& localVectorAssembler_;
  VectorType& vector_;
}; // class LocalFaceVectorAssemblerWrapper

} // namespace internal
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_ASSEMBLER_WRAPPER_HH
<|endoftext|>


<commit_before>/**
* 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 <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

#include <string>

#include <glog/logging.h>

#include <process/future.hpp>
#include <process/reap.hpp>
#include <process/subprocess.hpp>

#include <stout/error.hpp>
#include <stout/lambda.hpp>
#include <stout/foreach.hpp>
#include <stout/option.hpp>
#include <stout/os.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>
#include <stout/unreachable.hpp>

using std::map;
using std::string;
using std::vector;

namespace process {
namespace internal {

// See the comment below as to why subprocess is passed to cleanup.
static void cleanup(
    const Future<Option<int>>& result,
    Promise<Option<int>>* promise,
    const Subprocess& subprocess)
{
  CHECK(!result.isPending());
  CHECK(!result.isDiscarded());

  if (result.isFailed()) {
    promise->fail(result.failure());
  } else {
    promise->set(result.get());
  }

  delete promise;
}

static void close(int stdinFd[2], int stdoutFd[2], int stderrFd[2])
{
  os::close(stdinFd[0]);
  os::close(stdinFd[1]);
  os::close(stdoutFd[0]);
  os::close(stdoutFd[1]);
  os::close(stderrFd[0]);
  os::close(stderrFd[1]);
}

// This function will invoke os::cloexec on all file descriptors in
// these pairs that are valid (i.e., >= 0).
static Try<Nothing> cloexec(int stdinFd[2], int stdoutFd[2], int stderrFd[2])
{
  int fd[6] = {
    stdinFd[0],
    stdinFd[1],
    stdoutFd[0],
    stdoutFd[1],
    stderrFd[0],
    stderrFd[1]
  };

  for (int i = 0; i < 6; i++) {
    if (fd[i] >= 0) {
      Try<Nothing> cloexec = os::cloexec(fd[i]);
      if (cloexec.isError()) {
        return Error(cloexec.error());
      }
    }
  }

  return Nothing();
}

}  // namespace internal {

static pid_t defaultClone(const lambda::function<int()>& func)
{
  pid_t pid = ::fork();
  if (pid == -1) {
    return -1;
  } else if (pid == 0) {
    // Child.
    ::exit(func());
    UNREACHABLE();
  } else {
    // Parent.
    return pid;
  }
}

// The main entry of the child process. Note that this function has to
// be async singal safe.
static int childMain(
    const string& path,
    char** argv,
    const Subprocess::IO& in,
    const Subprocess::IO& out,
    const Subprocess::IO& err,
    char** envp,
    const Option<lambda::function<int()>>& setup,
    int stdinFd[2],
    int stdoutFd[2],
    int stderrFd[2])
{
  // Close parent's end of the pipes.
  if (in.isPipe()) {
    while (::close(stdinFd[1]) == -1 && errno == EINTR);
  }
  if (out.isPipe()) {
    while (::close(stdoutFd[0]) == -1 && errno == EINTR);
  }
  if (err.isPipe()) {
    while (::close(stderrFd[0]) == -1 && errno == EINTR);
  }

  // Redirect I/O for stdin/stdout/stderr.
  while (::dup2(stdinFd[0], STDIN_FILENO) == -1 && errno == EINTR);
  while (::dup2(stdoutFd[1], STDOUT_FILENO) == -1 && errno == EINTR);
  while (::dup2(stderrFd[1], STDERR_FILENO) == -1 && errno == EINTR);

  // Close the copies. We need to make sure that we do not close the
  // file descriptor assigned to stdin/stdout/stderr in case the
  // parent has closed stdin/stdout/stderr when calling this
  // function (in that case, a dup'ed file descriptor may have the
  // same file descriptor number as stdin/stdout/stderr).
  if (stdinFd[0] != STDIN_FILENO &&
      stdinFd[0] != STDOUT_FILENO &&
      stdinFd[0] != STDERR_FILENO) {
    while (::close(stdinFd[0]) == -1 && errno == EINTR);
  }
  if (stdoutFd[1] != STDIN_FILENO &&
      stdoutFd[1] != STDOUT_FILENO &&
      stdoutFd[1] != STDERR_FILENO) {
    while (::close(stdoutFd[1]) == -1 && errno == EINTR);
  }
  if (stderrFd[1] != STDIN_FILENO &&
      stderrFd[1] != STDOUT_FILENO &&
      stderrFd[1] != STDERR_FILENO) {
    while (::close(stderrFd[1]) == -1 && errno == EINTR);
  }

  if (setup.isSome()) {
    int status = setup.get()();
    if (status != 0) {
      _exit(status);
    }
  }

  os::execvpe(path.c_str(), argv, envp);

  ABORT(string("Failed to os::execvpe in childMain: ") + strerror(errno));
}

Try<Subprocess> subprocess(
    const string& path,
    vector<string> argv,
    const Subprocess::IO& in,
    const Subprocess::IO& out,
    const Subprocess::IO& err,
    const Option<flags::FlagsBase>& flags,
    const Option<map<string, string>>& environment,
    const Option<lambda::function<int()>>& setup,
    const Option<lambda::function<
        pid_t(const lambda::function<int()>&)>>& _clone)
{
  // File descriptors for redirecting stdin/stdout/stderr. These file
  // descriptors are used for different purposes depending on the
  // specified I/O modes. If the mode is PIPE, the two file
  // descriptors represent two ends of a pipe. If the mode is PATH or
  // FD, only one of the two file descriptors is used. Our protocol
  // here is that index 0 is always for reading, and index 1 is always
  // for writing (similar to the pipe semantics).
  int stdinFd[2] = { -1, -1 };
  int stdoutFd[2] = { -1, -1 };
  int stderrFd[2] = { -1, -1 };

  // Prepare the file descriptor(s) for stdin.
  switch (in.mode) {
    case Subprocess::IO::FD: {
      stdinFd[0] = ::dup(in.fd.get());
      if (stdinFd[0] == -1) {
        return ErrnoError("Failed to dup");
      }
      break;
    }
    case Subprocess::IO::PIPE: {
      if (::pipe(stdinFd) == -1) {
        return ErrnoError("Failed to create pipe");
      }
      break;
    }
    case Subprocess::IO::PATH: {
      Try<int> open = os::open(in.path.get(), O_RDONLY | O_CLOEXEC);
      if (open.isError()) {
        return Error(
            "Failed to open '" + in.path.get() + "': " + open.error());
      }
      stdinFd[0] = open.get();
      break;
    }
    default:
      UNREACHABLE();
  }

  // Prepare the file descriptor(s) for stdout.
  switch (out.mode) {
    case Subprocess::IO::FD: {
      stdoutFd[1] = ::dup(out.fd.get());
      if (stdoutFd[1] == -1) {
        // Save the errno as 'close' below might overwrite it.
        ErrnoError error("Failed to dup");
        internal::close(stdinFd, stdoutFd, stderrFd);
        return error;
      }
      break;
    }
    case Subprocess::IO::PIPE: {
      if (::pipe(stdoutFd) == -1) {
        // Save the errno as 'close' below might overwrite it.
        ErrnoError error("Failed to create pipe");
        internal::close(stdinFd, stdoutFd, stderrFd);
        return error;
      }
      break;
    }
    case Subprocess::IO::PATH: {
      Try<int> open = os::open(
          out.path.get(),
          O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC,
          S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

      if (open.isError()) {
        internal::close(stdinFd, stdoutFd, stderrFd);
        return Error(
            "Failed to open '" + out.path.get() + "': " + open.error());
      }
      stdoutFd[1] = open.get();
      break;
    }
    default:
      UNREACHABLE();
  }

  // Prepare the file descriptor(s) for stderr.
  switch (err.mode) {
    case Subprocess::IO::FD: {
      stderrFd[1] = ::dup(err.fd.get());
      if (stderrFd[1] == -1) {
        // Save the errno as 'close' below might overwrite it.
        ErrnoError error("Failed to dup");
        internal::close(stdinFd, stdoutFd, stderrFd);
        return error;
      }
      break;
    }
    case Subprocess::IO::PIPE: {
      if (::pipe(stderrFd) == -1) {
        // Save the errno as 'close' below might overwrite it.
        ErrnoError error("Failed to create pipe");
        internal::close(stdinFd, stdoutFd, stderrFd);
        return error;
      }
      break;
    }
    case Subprocess::IO::PATH: {
      Try<int> open = os::open(
          err.path.get(),
          O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC,
          S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

      if (open.isError()) {
        internal::close(stdinFd, stdoutFd, stderrFd);
        return Error(
            "Failed to open '" + err.path.get() + "': " + open.error());
      }
      stderrFd[1] = open.get();
      break;
    }
    default:
      UNREACHABLE();
  }

  // TODO(jieyu): Consider using O_CLOEXEC for atomic close-on-exec.
  Try<Nothing> cloexec = internal::cloexec(stdinFd, stdoutFd, stderrFd);
  if (cloexec.isError()) {
    internal::close(stdinFd, stdoutFd, stderrFd);
    return Error("Failed to cloexec: " + cloexec.error());
  }

  // Prepare the arguments. If the user specifies the 'flags', we will
  // stringify them and append them to the existing arguments.
  if (flags.isSome()) {
    foreachpair (const string& name, const flags::Flag& flag, flags.get()) {
      Option<string> value = flag.stringify(flags.get());
      if (value.isSome()) {
        argv.push_back("--" + name + "=" + value.get());
      }
    }
  }

  // The real arguments that will be passed to 'os::execvpe'. We need
  // to construct them here before doing the clone as it might not be
  // async signal safe to perform the memory allocation.
  char** _argv = new char*[argv.size() + 1];
  for (int i = 0; i < argv.size(); i++) {
    _argv[i] = (char*) argv[i].c_str();
  }
  _argv[argv.size()] = NULL;

  // Like above, we need to construct the environment that we'll pass
  // to 'os::execvpe' as it might not be async-safe to perform the
  // memory allocations.
  char** envp = os::environ();

  if (environment.isSome()) {
    // NOTE: We add 1 to the size for a NULL terminator.
    envp = new char*[environment.get().size() + 1];

    size_t index = 0;
    foreachpair (const string& key, const string& value, environment.get()) {
      string entry = key + "=" + value;
      envp[index] = new char[entry.size() + 1];
      strncpy(envp[index], entry.c_str(), entry.size() + 1);
      ++index;
    }

    envp[index] = NULL;
  }

  // Determine the function to clone the child process. If the user
  // does not specify the clone function, we will use the default.
  lambda::function<pid_t(const lambda::function<int()>&)> clone =
    (_clone.isSome() ? _clone.get() : defaultClone);

  // Now, clone the child process.
  pid_t pid = clone(lambda::bind(
      &childMain,
      path,
      _argv,
      in,
      out,
      err,
      envp,
      setup,
      stdinFd,
      stdoutFd,
      stderrFd));

  delete[] _argv;

  // Need to delete 'envp' if we had environment variables passed to
  // us and we needed to allocate the space.
  if (environment.isSome()) {
    CHECK_NE(os::environ(), envp);
    delete[] envp;
  }

  if (pid == -1) {
    // Save the errno as 'close' below might overwrite it.
    ErrnoError error("Failed to clone");
    internal::close(stdinFd, stdoutFd, stderrFd);
    return error;
  }

  // Parent.
  Subprocess process;
  process.data->pid = pid;

  // Close the file descriptors that are created by this function. For
  // pipes, we close the child ends and store the parent ends (see the
  // code below).
  os::close(stdinFd[0]);
  os::close(stdoutFd[1]);
  os::close(stderrFd[1]);

  // If the mode is PIPE, store the parent side of the pipe so that
  // the user can communicate with the subprocess.
  if (in.mode == Subprocess::IO::PIPE) {
    process.data->in = stdinFd[1];
  }
  if (out.mode == Subprocess::IO::PIPE) {
    process.data->out = stdoutFd[0];
  }
  if (err.mode == Subprocess::IO::PIPE) {
    process.data->err = stderrFd[0];
  }

  // Rather than directly exposing the future from process::reap, we
  // must use an explicit promise so that we can ensure we can receive
  // the termination signal. Otherwise, the caller can discard the
  // reap future, and we will not know when it is safe to close the
  // file descriptors.
  Promise<Option<int>>* promise = new Promise<Option<int>>();
  process.data->status = promise->future();

  // We need to bind a copy of this Subprocess into the onAny callback
  // below to ensure that we don't close the file descriptors before
  // the subprocess has terminated (i.e., because the caller doesn't
  // keep a copy of this Subprocess around themselves).
  process::reap(process.data->pid)
    .onAny(lambda::bind(internal::cleanup, lambda::_1, promise, process));

  return process;
}

}  // namespace process {
<commit_msg>Do not retry close on EINTR.<commit_after>/**
* 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 <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

#include <string>

#include <glog/logging.h>

#include <process/future.hpp>
#include <process/reap.hpp>
#include <process/subprocess.hpp>

#include <stout/error.hpp>
#include <stout/lambda.hpp>
#include <stout/foreach.hpp>
#include <stout/option.hpp>
#include <stout/os.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>
#include <stout/unreachable.hpp>

using std::map;
using std::string;
using std::vector;

namespace process {
namespace internal {

// See the comment below as to why subprocess is passed to cleanup.
static void cleanup(
    const Future<Option<int>>& result,
    Promise<Option<int>>* promise,
    const Subprocess& subprocess)
{
  CHECK(!result.isPending());
  CHECK(!result.isDiscarded());

  if (result.isFailed()) {
    promise->fail(result.failure());
  } else {
    promise->set(result.get());
  }

  delete promise;
}

static void close(int stdinFd[2], int stdoutFd[2], int stderrFd[2])
{
  os::close(stdinFd[0]);
  os::close(stdinFd[1]);
  os::close(stdoutFd[0]);
  os::close(stdoutFd[1]);
  os::close(stderrFd[0]);
  os::close(stderrFd[1]);
}

// This function will invoke os::cloexec on all file descriptors in
// these pairs that are valid (i.e., >= 0).
static Try<Nothing> cloexec(int stdinFd[2], int stdoutFd[2], int stderrFd[2])
{
  int fd[6] = {
    stdinFd[0],
    stdinFd[1],
    stdoutFd[0],
    stdoutFd[1],
    stderrFd[0],
    stderrFd[1]
  };

  for (int i = 0; i < 6; i++) {
    if (fd[i] >= 0) {
      Try<Nothing> cloexec = os::cloexec(fd[i]);
      if (cloexec.isError()) {
        return Error(cloexec.error());
      }
    }
  }

  return Nothing();
}

}  // namespace internal {

static pid_t defaultClone(const lambda::function<int()>& func)
{
  pid_t pid = ::fork();
  if (pid == -1) {
    return -1;
  } else if (pid == 0) {
    // Child.
    ::exit(func());
    UNREACHABLE();
  } else {
    // Parent.
    return pid;
  }
}

// The main entry of the child process. Note that this function has to
// be async singal safe.
static int childMain(
    const string& path,
    char** argv,
    const Subprocess::IO& in,
    const Subprocess::IO& out,
    const Subprocess::IO& err,
    char** envp,
    const Option<lambda::function<int()>>& setup,
    int stdinFd[2],
    int stdoutFd[2],
    int stderrFd[2])
{
  // Close parent's end of the pipes.
  if (in.isPipe()) {
    ::close(stdinFd[1]);
  }
  if (out.isPipe()) {
    ::close(stdoutFd[0]);
  }
  if (err.isPipe()) {
    ::close(stderrFd[0]);
  }

  // Redirect I/O for stdin/stdout/stderr.
  while (::dup2(stdinFd[0], STDIN_FILENO) == -1 && errno == EINTR);
  while (::dup2(stdoutFd[1], STDOUT_FILENO) == -1 && errno == EINTR);
  while (::dup2(stderrFd[1], STDERR_FILENO) == -1 && errno == EINTR);

  // Close the copies. We need to make sure that we do not close the
  // file descriptor assigned to stdin/stdout/stderr in case the
  // parent has closed stdin/stdout/stderr when calling this
  // function (in that case, a dup'ed file descriptor may have the
  // same file descriptor number as stdin/stdout/stderr).
  if (stdinFd[0] != STDIN_FILENO &&
      stdinFd[0] != STDOUT_FILENO &&
      stdinFd[0] != STDERR_FILENO) {
    ::close(stdinFd[0]);
  }
  if (stdoutFd[1] != STDIN_FILENO &&
      stdoutFd[1] != STDOUT_FILENO &&
      stdoutFd[1] != STDERR_FILENO) {
    ::close(stdoutFd[1]);
  }
  if (stderrFd[1] != STDIN_FILENO &&
      stderrFd[1] != STDOUT_FILENO &&
      stderrFd[1] != STDERR_FILENO) {
    ::close(stderrFd[1]);
  }

  if (setup.isSome()) {
    int status = setup.get()();
    if (status != 0) {
      _exit(status);
    }
  }

  os::execvpe(path.c_str(), argv, envp);

  ABORT(string("Failed to os::execvpe in childMain: ") + strerror(errno));
}

Try<Subprocess> subprocess(
    const string& path,
    vector<string> argv,
    const Subprocess::IO& in,
    const Subprocess::IO& out,
    const Subprocess::IO& err,
    const Option<flags::FlagsBase>& flags,
    const Option<map<string, string>>& environment,
    const Option<lambda::function<int()>>& setup,
    const Option<lambda::function<
        pid_t(const lambda::function<int()>&)>>& _clone)
{
  // File descriptors for redirecting stdin/stdout/stderr. These file
  // descriptors are used for different purposes depending on the
  // specified I/O modes. If the mode is PIPE, the two file
  // descriptors represent two ends of a pipe. If the mode is PATH or
  // FD, only one of the two file descriptors is used. Our protocol
  // here is that index 0 is always for reading, and index 1 is always
  // for writing (similar to the pipe semantics).
  int stdinFd[2] = { -1, -1 };
  int stdoutFd[2] = { -1, -1 };
  int stderrFd[2] = { -1, -1 };

  // Prepare the file descriptor(s) for stdin.
  switch (in.mode) {
    case Subprocess::IO::FD: {
      stdinFd[0] = ::dup(in.fd.get());
      if (stdinFd[0] == -1) {
        return ErrnoError("Failed to dup");
      }
      break;
    }
    case Subprocess::IO::PIPE: {
      if (::pipe(stdinFd) == -1) {
        return ErrnoError("Failed to create pipe");
      }
      break;
    }
    case Subprocess::IO::PATH: {
      Try<int> open = os::open(in.path.get(), O_RDONLY | O_CLOEXEC);
      if (open.isError()) {
        return Error(
            "Failed to open '" + in.path.get() + "': " + open.error());
      }
      stdinFd[0] = open.get();
      break;
    }
    default:
      UNREACHABLE();
  }

  // Prepare the file descriptor(s) for stdout.
  switch (out.mode) {
    case Subprocess::IO::FD: {
      stdoutFd[1] = ::dup(out.fd.get());
      if (stdoutFd[1] == -1) {
        // Save the errno as 'close' below might overwrite it.
        ErrnoError error("Failed to dup");
        internal::close(stdinFd, stdoutFd, stderrFd);
        return error;
      }
      break;
    }
    case Subprocess::IO::PIPE: {
      if (::pipe(stdoutFd) == -1) {
        // Save the errno as 'close' below might overwrite it.
        ErrnoError error("Failed to create pipe");
        internal::close(stdinFd, stdoutFd, stderrFd);
        return error;
      }
      break;
    }
    case Subprocess::IO::PATH: {
      Try<int> open = os::open(
          out.path.get(),
          O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC,
          S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

      if (open.isError()) {
        internal::close(stdinFd, stdoutFd, stderrFd);
        return Error(
            "Failed to open '" + out.path.get() + "': " + open.error());
      }
      stdoutFd[1] = open.get();
      break;
    }
    default:
      UNREACHABLE();
  }

  // Prepare the file descriptor(s) for stderr.
  switch (err.mode) {
    case Subprocess::IO::FD: {
      stderrFd[1] = ::dup(err.fd.get());
      if (stderrFd[1] == -1) {
        // Save the errno as 'close' below might overwrite it.
        ErrnoError error("Failed to dup");
        internal::close(stdinFd, stdoutFd, stderrFd);
        return error;
      }
      break;
    }
    case Subprocess::IO::PIPE: {
      if (::pipe(stderrFd) == -1) {
        // Save the errno as 'close' below might overwrite it.
        ErrnoError error("Failed to create pipe");
        internal::close(stdinFd, stdoutFd, stderrFd);
        return error;
      }
      break;
    }
    case Subprocess::IO::PATH: {
      Try<int> open = os::open(
          err.path.get(),
          O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC,
          S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

      if (open.isError()) {
        internal::close(stdinFd, stdoutFd, stderrFd);
        return Error(
            "Failed to open '" + err.path.get() + "': " + open.error());
      }
      stderrFd[1] = open.get();
      break;
    }
    default:
      UNREACHABLE();
  }

  // TODO(jieyu): Consider using O_CLOEXEC for atomic close-on-exec.
  Try<Nothing> cloexec = internal::cloexec(stdinFd, stdoutFd, stderrFd);
  if (cloexec.isError()) {
    internal::close(stdinFd, stdoutFd, stderrFd);
    return Error("Failed to cloexec: " + cloexec.error());
  }

  // Prepare the arguments. If the user specifies the 'flags', we will
  // stringify them and append them to the existing arguments.
  if (flags.isSome()) {
    foreachpair (const string& name, const flags::Flag& flag, flags.get()) {
      Option<string> value = flag.stringify(flags.get());
      if (value.isSome()) {
        argv.push_back("--" + name + "=" + value.get());
      }
    }
  }

  // The real arguments that will be passed to 'os::execvpe'. We need
  // to construct them here before doing the clone as it might not be
  // async signal safe to perform the memory allocation.
  char** _argv = new char*[argv.size() + 1];
  for (int i = 0; i < argv.size(); i++) {
    _argv[i] = (char*) argv[i].c_str();
  }
  _argv[argv.size()] = NULL;

  // Like above, we need to construct the environment that we'll pass
  // to 'os::execvpe' as it might not be async-safe to perform the
  // memory allocations.
  char** envp = os::environ();

  if (environment.isSome()) {
    // NOTE: We add 1 to the size for a NULL terminator.
    envp = new char*[environment.get().size() + 1];

    size_t index = 0;
    foreachpair (const string& key, const string& value, environment.get()) {
      string entry = key + "=" + value;
      envp[index] = new char[entry.size() + 1];
      strncpy(envp[index], entry.c_str(), entry.size() + 1);
      ++index;
    }

    envp[index] = NULL;
  }

  // Determine the function to clone the child process. If the user
  // does not specify the clone function, we will use the default.
  lambda::function<pid_t(const lambda::function<int()>&)> clone =
    (_clone.isSome() ? _clone.get() : defaultClone);

  // Now, clone the child process.
  pid_t pid = clone(lambda::bind(
      &childMain,
      path,
      _argv,
      in,
      out,
      err,
      envp,
      setup,
      stdinFd,
      stdoutFd,
      stderrFd));

  delete[] _argv;

  // Need to delete 'envp' if we had environment variables passed to
  // us and we needed to allocate the space.
  if (environment.isSome()) {
    CHECK_NE(os::environ(), envp);
    delete[] envp;
  }

  if (pid == -1) {
    // Save the errno as 'close' below might overwrite it.
    ErrnoError error("Failed to clone");
    internal::close(stdinFd, stdoutFd, stderrFd);
    return error;
  }

  // Parent.
  Subprocess process;
  process.data->pid = pid;

  // Close the file descriptors that are created by this function. For
  // pipes, we close the child ends and store the parent ends (see the
  // code below).
  os::close(stdinFd[0]);
  os::close(stdoutFd[1]);
  os::close(stderrFd[1]);

  // If the mode is PIPE, store the parent side of the pipe so that
  // the user can communicate with the subprocess.
  if (in.mode == Subprocess::IO::PIPE) {
    process.data->in = stdinFd[1];
  }
  if (out.mode == Subprocess::IO::PIPE) {
    process.data->out = stdoutFd[0];
  }
  if (err.mode == Subprocess::IO::PIPE) {
    process.data->err = stderrFd[0];
  }

  // Rather than directly exposing the future from process::reap, we
  // must use an explicit promise so that we can ensure we can receive
  // the termination signal. Otherwise, the caller can discard the
  // reap future, and we will not know when it is safe to close the
  // file descriptors.
  Promise<Option<int>>* promise = new Promise<Option<int>>();
  process.data->status = promise->future();

  // We need to bind a copy of this Subprocess into the onAny callback
  // below to ensure that we don't close the file descriptors before
  // the subprocess has terminated (i.e., because the caller doesn't
  // keep a copy of this Subprocess around themselves).
  process::reap(process.data->pid)
    .onAny(lambda::bind(internal::cleanup, lambda::_1, promise, process));

  return process;
}

}  // namespace process {
<|endoftext|>


<commit_before>#include <cmath>
#include <functional>
#include <set>
#include <vector>

#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"

#include "png.h"

void IterateCubicBeziers(NSVGshape* shape, const std::function<void(const float*)>& f) {
    for (auto path = shape->paths; path; path = path->next) {
        for (size_t i = 0; i + 3 < path->npts; i += 3) {
            auto pts = &path->pts[i << 1];
            f(pts);
        }
    }
}

double CubicBezier(double t, double p0, double p1, double p2, double p3) {
    return (1.0 - t) * (1.0 - t) * (1.0 - t) * p0 + 3.0 * (1.0 - t) * (1.0 - t) * t * p1 + 3.0 * (1.0 - t) * t * t * p2 + t * t * t * p3;
}

std::set<double> ActiveEdges(NSVGshape* shape, double y) {
    std::set<double> ret;

    IterateCubicBeziers(shape, [&](const float* pts) {
        constexpr auto step = 0.00005;
        constexpr auto threshold = 0.005;
        constexpr auto gapThreshold = 8 * threshold;
        for (auto t = 0.0; t <= 1.0; t += step) {
            auto by = CubicBezier(t, pts[1], pts[3], pts[5], pts[7]);
            if (std::fabs(y - by) < threshold) {
                ret.insert(std::round(CubicBezier(t, pts[0], pts[2], pts[4], pts[6]) / gapThreshold) * gapThreshold);
            }
        }
    });

    return ret;
}

double Distance(NSVGimage* svg, double x, double y) {
    double ret2 = svg->width * svg->width + svg->height * svg->height;

    for (auto shape = svg->shapes; shape; shape = shape->next) {
        IterateCubicBeziers(shape, [&](const float* pts) {
            constexpr auto step = 0.00005;
            for (auto t = 0.0; t <= 1.0; t += step) {
                auto yd = std::fabs(y - CubicBezier(t, pts[1], pts[3], pts[5], pts[7]));
                auto yd2 = yd * yd;
                if (yd2 > ret2) { continue; }

                auto xd = std::fabs(x - CubicBezier(t, pts[0], pts[2], pts[4], pts[6]));
                auto xd2 = xd * xd;
                if (xd2 > ret2) { continue; }

                auto d2 = yd2 + xd2;
                if (d2 < ret2) {
                    ret2 = d2;
                }
            }
        });
    }

    return sqrt(ret2);
}

bool IsInsideActiveEdges(const std::set<double>& activeEdges, double x) {
    auto ret = false;
    for (auto& edge : activeEdges) {
        if (edge > x) {
            break;
        }
        ret = !ret;
    }
    return ret;
}

struct Pixel {
    uint16_t g = htons(std::numeric_limits<uint16_t>::max());
    uint16_t a;
};

void GetRowPixels(std::vector<Pixel>& pixels, NSVGimage* svg, double svgY, double range) {
    std::vector<std::set<double>> activeEdges;
    for (auto shape = svg->shapes; shape; shape = shape->next) {
        activeEdges.emplace_back(ActiveEdges(shape, svgY));
    }

    const auto scale = (double)pixels.size() / svg->width;

    for (size_t x = 0; x < pixels.size(); ++x) {
        double svgX = 0.5 + x / scale;
        auto d = -Distance(svg, svgX, svgY);

        for (auto& ae : activeEdges) {
            if (IsInsideActiveEdges(ae, svgX)) {
                d = -d;
                break;
            }
        }

        pixels[x].a = htons(std::numeric_limits<uint16_t>::max() * (0.5 * std::min(std::max((scale * d) / range, -1.0), 1.0) + 0.5));
    }
}

bool GeneratePNG(NSVGimage* svg, FILE* f, size_t outputWidth, size_t outputHeight, double range) {
    std::vector<Pixel> pixels;

    auto pngWrite = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    if (!pngWrite) {
        fprintf(stderr, "unable to allocate png write struct\n");
        return false;
    }

    auto pngInfo = png_create_info_struct(pngWrite);
    if (!pngInfo) {
        fprintf(stderr, "unable to allocate png info struct\n");
        png_destroy_write_struct(&pngWrite, nullptr);
        return false;
    }

    if (setjmp(png_jmpbuf(pngWrite))) {
        fprintf(stderr, "error generating png\n");
        png_free_data(pngWrite, pngInfo, PNG_FREE_ALL, -1);
        png_destroy_write_struct(&pngWrite, nullptr);
        return false;
    }

    png_init_io(pngWrite, f);
    png_set_IHDR(pngWrite, pngInfo, outputWidth, outputHeight, 16, PNG_COLOR_TYPE_GRAY_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    png_write_info(pngWrite, pngInfo);

    pixels.resize(outputWidth);

    for (size_t y = 0; y < outputHeight; ++y) {
        double svgY = 0.5 + (double)y * svg->height / outputHeight;
        GetRowPixels(pixels, svg, svgY, range);
        png_write_row(pngWrite, reinterpret_cast<png_const_bytep>(pixels.data()));
        printf("\b\b\b\b\b\b\b\b\b\b\b\b\b%zu / %zu", y, outputHeight);
        fflush(stdout);
    }
    printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");

    png_write_end(pngWrite, nullptr);

    png_free_data(pngWrite, pngInfo, PNG_FREE_ALL, -1);
    png_destroy_write_struct(&pngWrite, nullptr);
    return true;
}

int main(int argc, const char* argv[]) {
    if (argc < 6) {
        printf("usage: %s input output width height range\n", argv[0]);
        return 1;
    }

    const auto input = argv[1];
    const auto output = argv[2];
    const auto outputWidth = atoi(argv[3]);
    const auto outputHeight = atoi(argv[4]);
    const auto range = atoi(argv[5]);

    auto svg = nsvgParseFromFile(input, "px", 96.0);
    if (!svg) {
        fprintf(stderr, "unable to open svg\n");
        return 1;
    }

    auto f = fopen(output, "wb");
    if (!f) {
        fprintf(stderr, "unable to open output file for writing\n");
        nsvgDelete(svg);
        return 1;
    }

    auto success = GeneratePNG(svg, f, outputWidth, outputHeight, range);

    fclose(f);
    nsvgDelete(svg);

    return success ? 0 : 1;
}<commit_msg>sdf-generator constant tweaking<commit_after>#include <cmath>
#include <functional>
#include <set>
#include <vector>

#define NANOSVG_IMPLEMENTATION
#include "nanosvg.h"

#include "png.h"

void IterateCubicBeziers(NSVGshape* shape, const std::function<void(const float*)>& f) {
    for (auto path = shape->paths; path; path = path->next) {
        for (size_t i = 0; i + 3 < path->npts; i += 3) {
            auto pts = &path->pts[i << 1];
            f(pts);
        }
    }
}

double CubicBezier(double t, double p0, double p1, double p2, double p3) {
    return (1.0 - t) * (1.0 - t) * (1.0 - t) * p0 + 3.0 * (1.0 - t) * (1.0 - t) * t * p1 + 3.0 * (1.0 - t) * t * t * p2 + t * t * t * p3;
}

std::set<double> ActiveEdges(NSVGshape* shape, double y) {
    std::set<double> ret;

    IterateCubicBeziers(shape, [&](const float* pts) {
        constexpr auto step = 0.00005;
        constexpr auto threshold = 0.005;
        constexpr auto gapThreshold = 16 * threshold;
        for (auto t = 0.0; t <= 1.0; t += step) {
            auto by = CubicBezier(t, pts[1], pts[3], pts[5], pts[7]);
            if (std::fabs(y - by) < threshold) {
                ret.insert(std::round(CubicBezier(t, pts[0], pts[2], pts[4], pts[6]) / gapThreshold) * gapThreshold);
            }
        }
    });

    return ret;
}

double Distance(NSVGimage* svg, double x, double y) {
    double ret2 = svg->width * svg->width + svg->height * svg->height;

    for (auto shape = svg->shapes; shape; shape = shape->next) {
        IterateCubicBeziers(shape, [&](const float* pts) {
            constexpr auto step = 0.00005;
            for (auto t = 0.0; t <= 1.0; t += step) {
                auto yd = std::fabs(y - CubicBezier(t, pts[1], pts[3], pts[5], pts[7]));
                auto yd2 = yd * yd;
                if (yd2 > ret2) { continue; }

                auto xd = std::fabs(x - CubicBezier(t, pts[0], pts[2], pts[4], pts[6]));
                auto xd2 = xd * xd;
                if (xd2 > ret2) { continue; }

                auto d2 = yd2 + xd2;
                if (d2 < ret2) {
                    ret2 = d2;
                }
            }
        });
    }

    return sqrt(ret2);
}

bool IsInsideActiveEdges(const std::set<double>& activeEdges, double x) {
    auto ret = false;
    for (auto& edge : activeEdges) {
        if (edge > x) {
            break;
        }
        ret = !ret;
    }
    return ret;
}

struct Pixel {
    uint16_t g = htons(std::numeric_limits<uint16_t>::max());
    uint16_t a;
};

void GetRowPixels(std::vector<Pixel>& pixels, NSVGimage* svg, double svgY, double range) {
    std::vector<std::set<double>> activeEdges;
    for (auto shape = svg->shapes; shape; shape = shape->next) {
        activeEdges.emplace_back(ActiveEdges(shape, svgY));
    }

    const auto scale = (double)pixels.size() / svg->width;

    for (size_t x = 0; x < pixels.size(); ++x) {
        double svgX = 0.5 + x / scale;
        auto d = -Distance(svg, svgX, svgY);

        for (auto& ae : activeEdges) {
            if (IsInsideActiveEdges(ae, svgX)) {
                d = -d;
                break;
            }
        }

        pixels[x].a = htons(std::numeric_limits<uint16_t>::max() * (0.5 * std::min(std::max((scale * d) / range, -1.0), 1.0) + 0.5));
    }
}

bool GeneratePNG(NSVGimage* svg, FILE* f, size_t outputWidth, size_t outputHeight, double range) {
    std::vector<Pixel> pixels;

    auto pngWrite = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    if (!pngWrite) {
        fprintf(stderr, "unable to allocate png write struct\n");
        return false;
    }

    auto pngInfo = png_create_info_struct(pngWrite);
    if (!pngInfo) {
        fprintf(stderr, "unable to allocate png info struct\n");
        png_destroy_write_struct(&pngWrite, nullptr);
        return false;
    }

    if (setjmp(png_jmpbuf(pngWrite))) {
        fprintf(stderr, "error generating png\n");
        png_free_data(pngWrite, pngInfo, PNG_FREE_ALL, -1);
        png_destroy_write_struct(&pngWrite, nullptr);
        return false;
    }

    png_init_io(pngWrite, f);
    png_set_IHDR(pngWrite, pngInfo, outputWidth, outputHeight, 16, PNG_COLOR_TYPE_GRAY_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    png_write_info(pngWrite, pngInfo);

    pixels.resize(outputWidth);

    for (size_t y = 0; y < outputHeight; ++y) {
        double svgY = 0.5 + (double)y * svg->height / outputHeight;
        GetRowPixels(pixels, svg, svgY, range);
        png_write_row(pngWrite, reinterpret_cast<png_const_bytep>(pixels.data()));
        printf("\b\b\b\b\b\b\b\b\b\b\b\b\b%zu / %zu", y, outputHeight);
        fflush(stdout);
    }
    printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");

    png_write_end(pngWrite, nullptr);

    png_free_data(pngWrite, pngInfo, PNG_FREE_ALL, -1);
    png_destroy_write_struct(&pngWrite, nullptr);
    return true;
}

int main(int argc, const char* argv[]) {
    if (argc < 6) {
        printf("usage: %s input output width height range\n", argv[0]);
        return 1;
    }

    const auto input = argv[1];
    const auto output = argv[2];
    const auto outputWidth = atoi(argv[3]);
    const auto outputHeight = atoi(argv[4]);
    const auto range = atoi(argv[5]);

    auto svg = nsvgParseFromFile(input, "px", 96.0);
    if (!svg) {
        fprintf(stderr, "unable to open svg\n");
        return 1;
    }

    auto f = fopen(output, "wb");
    if (!f) {
        fprintf(stderr, "unable to open output file for writing\n");
        nsvgDelete(svg);
        return 1;
    }

    auto success = GeneratePNG(svg, f, outputWidth, outputHeight, range);

    fclose(f);
    nsvgDelete(svg);

    return success ? 0 : 1;
}<|endoftext|>


<commit_before>// Implement a basic calculator to evaluate a simple expression string.

// The expression string may contain open ( and closing parentheses ), the plus
// + or minus sign -, non-negative integers and empty spaces .

// The expression string contains only non-negative integers, +, -, *, /
// operators , open ( and closing parentheses ) and empty spaces . The integer
// division should truncate toward zero.

// You may assume that the given expression is always valid. All intermediate
// results will be in the range of [-2147483648, 2147483647].

// Some examples:

// "1 + 1" = 2
// " 6-4 / 2 " = 4
// "2*(5+5*2)/3+(6/2+8)" = 21
// "(2+6* 3+5- (3*14/7+2)*5)+3"=-12

// Note: Do not use the eval built-in library function.

class Solution {
  public:
    int calculate(string s) {
        stack<long long> nums;
        stack<char> ops;

        auto calculate = [&]() {
            long long curr_num = nums.top();
            nums.pop();
            while (!ops.empty() && ops.top() != '(') {
                if (ops.top() == '*')
                    nums.top() *= curr_num;
                else if (ops.top() == '/')
                    nums.top() /= curr_num;
                else if (ops.top() == '+')
                    nums.top() += curr_num;
                else if (ops.top() == '-')
                    nums.top() -= curr_num;

                curr_num = nums.top();
                nums.pop();
                ops.pop();
            }
            nums.push(curr_num);
        };

        istringstream expin(s); // expression in
        char curr_char;
        long long curr_num;

        while (expin >> ws && !expin.eof()) {
            if (isdigit(expin.peek())) {
                expin >> curr_num;
                nums.push(curr_num);

                if (!ops.empty() && (ops.top() == '*' || ops.top() == '/'))
                    calculate();
            } else {
                expin >> curr_char;
                if (curr_char == ')') {
                    calculate();
                    ops.pop();
                } else {
                    if (curr_char == '+' || curr_char == '-')
                        calculate();
                    ops.push(curr_char);
                }
            }
        }

        calculate();

        return nums.empty() ? 0 : nums.top();
    }
};<commit_msg>772 bug fix unfinished<commit_after>// Implement a basic calculator to evaluate a simple expression string.

// The expression string may contain open ( and closing parentheses ), the plus
// + or minus sign -, non-negative integers and empty spaces .

// The expression string contains only non-negative integers, +, -, *, /
// operators , open ( and closing parentheses ) and empty spaces . The integer
// division should truncate toward zero.

// You may assume that the given expression is always valid. All intermediate
// results will be in the range of [-2147483648, 2147483647].

// Some examples:

// "1 + 1" = 2
// " 6-4 / 2 " = 4
// "2*(5+5*2)/3+(6/2+8)" = 21
// "(2+6* 3+5- (3*14/7+2)*5)+3"=-12

// Note: Do not use the eval built-in library function.

class Solution {
  public:
    int calculate(string s) {
        stack<long long> nums;
        stack<char> ops;

        auto muldiv = [&]() {
            long long curr_num = nums.top();
            nums.pop();
            while (!ops.empty() && ops.top() != '+' && ops.top() != '-') {
                if (ops.top() == '*')
                    nums.top() *= curr_num;
                else if (ops.top() == '/')
                    nums.top() /= curr_num;
                curr_num = nums.top();
                nums.pop();
                ops.pop();
            }
            nums.push(curr_num);
        };

        auto addminus = [&]() {
            long long curr_num = nums.top();
            nums.pop();
            while (!ops.empty()) {
                if (ops.top() == '+')
                    nums.top() += curr_num;
                else if (ops.top() == '-')
                    nums.top() -= curr_num;
                curr_num = nums.top();
                nums.pop();
                ops.pop();
            }
            nums.push(curr_num);
        };

        istringstream expin(s); // expression in
        char curr_char;
        long long curr_num;

        while (expin >> ws && !expin.eof()) {
            if (isdigit(expin.peek())) {
                expin >> curr_num;
                nums.push(curr_num);

                if (!ops.empty() && (ops.top() == '*' || ops.top() == '/'))
                    calculate();
            } else {
                expin >> curr_char;
                if (curr_char == ')') {
                    calculate();
                    ops.pop();
                } else {
                    if (curr_char == '+' || curr_char == '-')
                        calculate();
                    ops.push(curr_char);
                }
            }
        }

        calculate();

        return nums.empty() ? 0 : nums.top();
    }
};<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * 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 "common_throws.h"
#include "gc/accounting/card_table-inl.h"
#include "jni_internal.h"
#include "mirror/array.h"
#include "mirror/class.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "scoped_fast_native_object_access.h"

namespace art {

/*
 * We make guarantees about the atomicity of accesses to primitive variables.  These guarantees
 * also apply to elements of arrays. In particular, 8-bit, 16-bit, and 32-bit accesses must not
 * cause "word tearing".  Accesses to 64-bit array elements may be two 32-bit operations.
 * References are never torn regardless of the number of bits used to represent them.
 */

static void ThrowArrayStoreException_NotAnArray(const char* identifier, mirror::Object* array)
    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
  std::string actualType(PrettyTypeOf(array));
  Thread* self = Thread::Current();
  ThrowLocation throw_location = self->GetCurrentLocationForThrow();
  self->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;",
                           "%s of type %s is not an array", identifier, actualType.c_str());
}

static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst,
                             jint dstPos, jint length) {
  // The API is defined in terms of length, but length is somewhat overloaded so we use count.
  const jint count = length;
  ScopedFastNativeObjectAccess soa(env);

  // Null pointer checks.
  if (UNLIKELY(javaSrc == nullptr)) {
    ThrowNullPointerException(nullptr, "src == null");
    return;
  }
  if (UNLIKELY(javaDst == nullptr)) {
    ThrowNullPointerException(nullptr, "dst == null");
    return;
  }

  // Make sure source and destination are both arrays.
  mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
  if (UNLIKELY(!srcObject->IsArrayInstance())) {
    ThrowArrayStoreException_NotAnArray("source", srcObject);
    return;
  }
  mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
  if (UNLIKELY(!dstObject->IsArrayInstance())) {
    ThrowArrayStoreException_NotAnArray("destination", dstObject);
    return;
  }
  mirror::Array* srcArray = srcObject->AsArray();
  mirror::Array* dstArray = dstObject->AsArray();

  // Bounds checking.
  if (UNLIKELY(srcPos < 0) || UNLIKELY(dstPos < 0) || UNLIKELY(count < 0) ||
      UNLIKELY(srcPos > srcArray->GetLength() - count) ||
      UNLIKELY(dstPos > dstArray->GetLength() - count)) {
    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
    soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;",
                                   "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
                                   srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos,
                                   count);
    return;
  }

  mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType();
  mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType();
  Primitive::Type dstComponentPrimitiveType = dstComponentType->GetPrimitiveType();

  if (LIKELY(srcComponentType == dstComponentType)) {
    // Trivial assignability.
    switch (dstComponentPrimitiveType) {
      case Primitive::kPrimVoid:
        LOG(FATAL) << "Unreachable, cannot have arrays of type void";
        return;
      case Primitive::kPrimBoolean:
      case Primitive::kPrimByte:
        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 1U);
        dstArray->AsByteSizedArray()->Memmove(dstPos, srcArray->AsByteSizedArray(), srcPos, count);
        return;
      case Primitive::kPrimChar:
      case Primitive::kPrimShort:
        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 2U);
        dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count);
        return;
      case Primitive::kPrimInt:
      case Primitive::kPrimFloat:
        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U);
        dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count);
        return;
      case Primitive::kPrimLong:
      case Primitive::kPrimDouble:
        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U);
        dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count);
        return;
      case Primitive::kPrimNot: {
        mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>();
        mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>();
        dstObjArray->AssignableMemmove(dstPos, srcObjArray, srcPos, count);
        return;
      }
      default:
        LOG(FATAL) << "Unknown array type: " << PrettyTypeOf(srcArray);
        return;
    }
  }
  // If one of the arrays holds a primitive type the other array must hold the exact same type.
  if (UNLIKELY((dstComponentPrimitiveType != Primitive::kPrimNot) ||
               srcComponentType->IsPrimitive())) {
    std::string srcType(PrettyTypeOf(srcArray));
    std::string dstType(PrettyTypeOf(dstArray));
    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
    soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;",
                                   "Incompatible types: src=%s, dst=%s",
                                   srcType.c_str(), dstType.c_str());
    return;
  }
  // Arrays hold distinct types and so therefore can't alias - use memcpy instead of memmove.
  mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>();
  mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>();
  // If we're assigning into say Object[] then we don't need per element checks.
  if (dstComponentType->IsAssignableFrom(srcComponentType)) {
    dstObjArray->AssignableMemcpy(dstPos, srcObjArray, srcPos, count);
    return;
  }
  dstObjArray->AssignableCheckingMemcpy(dstPos, srcObjArray, srcPos, count, true);
}

static void System_arraycopyCharUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos,
                                          jobject javaDst, jint dstPos, jint count) {
  ScopedFastNativeObjectAccess soa(env);
  mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
  mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
  DCHECK(srcObject != nullptr);
  DCHECK(dstObject != nullptr);
  mirror::Array* srcArray = srcObject->AsArray();
  mirror::Array* dstArray = dstObject->AsArray();
  DCHECK_GE(srcPos, 0);
  DCHECK_GE(dstPos, 0);
  DCHECK_GE(count, 0);
  DCHECK_LE(srcPos + count, srcArray->GetLength());
  DCHECK_LE(dstPos + count, dstArray->GetLength());
  DCHECK_EQ(srcArray->GetClass(), dstArray->GetClass());
  DCHECK_EQ(srcArray->GetClass()->GetComponentType()->GetPrimitiveType(), Primitive::kPrimChar);
  dstArray->AsCharArray()->Memmove(dstPos, srcArray->AsCharArray(), srcPos, count);
}

static jint System_identityHashCode(JNIEnv* env, jclass, jobject javaObject) {
  if (UNLIKELY(javaObject == nullptr)) {
    return 0;
  }
  ScopedFastNativeObjectAccess soa(env);
  mirror::Object* o = soa.Decode<mirror::Object*>(javaObject);
  return static_cast<jint>(o->IdentityHashCode());
}

static JNINativeMethod gMethods[] = {
  NATIVE_METHOD(System, arraycopy, "!(Ljava/lang/Object;ILjava/lang/Object;II)V"),
  NATIVE_METHOD(System, arraycopyCharUnchecked, "!([CI[CII)V"),
  NATIVE_METHOD(System, identityHashCode, "!(Ljava/lang/Object;)I"),
};

void register_java_lang_System(JNIEnv* env) {
  REGISTER_NATIVE_METHODS("java/lang/System");
}

}  // namespace art
<commit_msg>am b2c369f7: Merge "Expanded native code to use arraycopy for specific data types."<commit_after>/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * 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 "common_throws.h"
#include "gc/accounting/card_table-inl.h"
#include "jni_internal.h"
#include "mirror/array.h"
#include "mirror/class.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "scoped_fast_native_object_access.h"

namespace art {

/*
 * We make guarantees about the atomicity of accesses to primitive variables.  These guarantees
 * also apply to elements of arrays. In particular, 8-bit, 16-bit, and 32-bit accesses must not
 * cause "word tearing".  Accesses to 64-bit array elements may be two 32-bit operations.
 * References are never torn regardless of the number of bits used to represent them.
 */

static void ThrowArrayStoreException_NotAnArray(const char* identifier, mirror::Object* array)
    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
  std::string actualType(PrettyTypeOf(array));
  Thread* self = Thread::Current();
  ThrowLocation throw_location = self->GetCurrentLocationForThrow();
  self->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;",
                           "%s of type %s is not an array", identifier, actualType.c_str());
}

static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst,
                             jint dstPos, jint length) {
  // The API is defined in terms of length, but length is somewhat overloaded so we use count.
  const jint count = length;
  ScopedFastNativeObjectAccess soa(env);

  // Null pointer checks.
  if (UNLIKELY(javaSrc == nullptr)) {
    ThrowNullPointerException(nullptr, "src == null");
    return;
  }
  if (UNLIKELY(javaDst == nullptr)) {
    ThrowNullPointerException(nullptr, "dst == null");
    return;
  }

  // Make sure source and destination are both arrays.
  mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
  if (UNLIKELY(!srcObject->IsArrayInstance())) {
    ThrowArrayStoreException_NotAnArray("source", srcObject);
    return;
  }
  mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
  if (UNLIKELY(!dstObject->IsArrayInstance())) {
    ThrowArrayStoreException_NotAnArray("destination", dstObject);
    return;
  }
  mirror::Array* srcArray = srcObject->AsArray();
  mirror::Array* dstArray = dstObject->AsArray();

  // Bounds checking.
  if (UNLIKELY(srcPos < 0) || UNLIKELY(dstPos < 0) || UNLIKELY(count < 0) ||
      UNLIKELY(srcPos > srcArray->GetLength() - count) ||
      UNLIKELY(dstPos > dstArray->GetLength() - count)) {
    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
    soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;",
                                   "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
                                   srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos,
                                   count);
    return;
  }

  mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType();
  mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType();
  Primitive::Type dstComponentPrimitiveType = dstComponentType->GetPrimitiveType();

  if (LIKELY(srcComponentType == dstComponentType)) {
    // Trivial assignability.
    switch (dstComponentPrimitiveType) {
      case Primitive::kPrimVoid:
        LOG(FATAL) << "Unreachable, cannot have arrays of type void";
        return;
      case Primitive::kPrimBoolean:
      case Primitive::kPrimByte:
        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 1U);
        dstArray->AsByteSizedArray()->Memmove(dstPos, srcArray->AsByteSizedArray(), srcPos, count);
        return;
      case Primitive::kPrimChar:
      case Primitive::kPrimShort:
        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 2U);
        dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count);
        return;
      case Primitive::kPrimInt:
      case Primitive::kPrimFloat:
        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U);
        dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count);
        return;
      case Primitive::kPrimLong:
      case Primitive::kPrimDouble:
        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U);
        dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count);
        return;
      case Primitive::kPrimNot: {
        mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>();
        mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>();
        dstObjArray->AssignableMemmove(dstPos, srcObjArray, srcPos, count);
        return;
      }
      default:
        LOG(FATAL) << "Unknown array type: " << PrettyTypeOf(srcArray);
        return;
    }
  }
  // If one of the arrays holds a primitive type the other array must hold the exact same type.
  if (UNLIKELY((dstComponentPrimitiveType != Primitive::kPrimNot) ||
               srcComponentType->IsPrimitive())) {
    std::string srcType(PrettyTypeOf(srcArray));
    std::string dstType(PrettyTypeOf(dstArray));
    ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
    soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;",
                                   "Incompatible types: src=%s, dst=%s",
                                   srcType.c_str(), dstType.c_str());
    return;
  }
  // Arrays hold distinct types and so therefore can't alias - use memcpy instead of memmove.
  mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>();
  mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>();
  // If we're assigning into say Object[] then we don't need per element checks.
  if (dstComponentType->IsAssignableFrom(srcComponentType)) {
    dstObjArray->AssignableMemcpy(dstPos, srcObjArray, srcPos, count);
    return;
  }
  dstObjArray->AssignableCheckingMemcpy(dstPos, srcObjArray, srcPos, count, true);
}

// Template to convert general array to that of its specific primitive type.
template <typename T>
inline T* AsPrimitiveArray(mirror::Array* array) {
  return down_cast<T*>(array);
}

template <typename T, Primitive::Type kPrimType>
inline void System_arraycopyTUnchecked(JNIEnv* env, jobject javaSrc, jint srcPos,
                                       jobject javaDst, jint dstPos, jint count) {
  ScopedFastNativeObjectAccess soa(env);
  mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
  mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
  DCHECK(dstObject != nullptr);
  mirror::Array* srcArray = srcObject->AsArray();
  mirror::Array* dstArray = dstObject->AsArray();
  DCHECK_GE(count, 0);
  DCHECK_EQ(srcArray->GetClass(), dstArray->GetClass());
  DCHECK_EQ(srcArray->GetClass()->GetComponentType()->GetPrimitiveType(), kPrimType);
  AsPrimitiveArray<T>(dstArray)->Memmove(dstPos, AsPrimitiveArray<T>(srcArray), srcPos, count);
}

static void System_arraycopyCharUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos,
                                          jobject javaDst, jint dstPos, jint count) {
  System_arraycopyTUnchecked<mirror::CharArray, Primitive::kPrimChar>(env, javaSrc, srcPos,
      javaDst, dstPos, count);
}

static void System_arraycopyByteUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos,
                                          jobject javaDst, jint dstPos, jint count) {
  System_arraycopyTUnchecked<mirror::ByteArray, Primitive::kPrimByte>(env, javaSrc, srcPos,
      javaDst, dstPos, count);
}

static void System_arraycopyShortUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos,
                                           jobject javaDst, jint dstPos, jint count) {
  System_arraycopyTUnchecked<mirror::ShortArray, Primitive::kPrimShort>(env, javaSrc, srcPos,
      javaDst, dstPos, count);
}

static void System_arraycopyIntUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos,
                                         jobject javaDst, jint dstPos, jint count) {
  System_arraycopyTUnchecked<mirror::IntArray, Primitive::kPrimInt>(env, javaSrc, srcPos,
      javaDst, dstPos, count);
}

static void System_arraycopyLongUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos,
                                          jobject javaDst, jint dstPos, jint count) {
  System_arraycopyTUnchecked<mirror::LongArray, Primitive::kPrimLong>(env, javaSrc, srcPos,
      javaDst, dstPos, count);
}

static void System_arraycopyFloatUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos,
                                           jobject javaDst, jint dstPos, jint count) {
  System_arraycopyTUnchecked<mirror::FloatArray, Primitive::kPrimFloat>(env, javaSrc, srcPos,
      javaDst, dstPos, count);
}

static void System_arraycopyDoubleUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos,
                                            jobject javaDst, jint dstPos, jint count) {
  System_arraycopyTUnchecked<mirror::DoubleArray, Primitive::kPrimDouble>(env, javaSrc, srcPos,
      javaDst, dstPos, count);
}

static void System_arraycopyBooleanUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos,
                                             jobject javaDst, jint dstPos, jint count) {
  System_arraycopyTUnchecked<mirror::BooleanArray, Primitive::kPrimBoolean>(env, javaSrc, srcPos,
      javaDst, dstPos, count);
}

static jint System_identityHashCode(JNIEnv* env, jclass, jobject javaObject) {
  if (UNLIKELY(javaObject == nullptr)) {
    return 0;
  }
  ScopedFastNativeObjectAccess soa(env);
  mirror::Object* o = soa.Decode<mirror::Object*>(javaObject);
  return static_cast<jint>(o->IdentityHashCode());
}

static JNINativeMethod gMethods[] = {
  NATIVE_METHOD(System, arraycopy, "!(Ljava/lang/Object;ILjava/lang/Object;II)V"),
  NATIVE_METHOD(System, arraycopyCharUnchecked, "!([CI[CII)V"),
  NATIVE_METHOD(System, arraycopyByteUnchecked, "!([BI[BII)V"),
  NATIVE_METHOD(System, arraycopyShortUnchecked, "!([SI[SII)V"),
  NATIVE_METHOD(System, arraycopyIntUnchecked, "!([II[III)V"),
  NATIVE_METHOD(System, arraycopyLongUnchecked, "!([JI[JII)V"),
  NATIVE_METHOD(System, arraycopyFloatUnchecked, "!([FI[FII)V"),
  NATIVE_METHOD(System, arraycopyDoubleUnchecked, "!([DI[DII)V"),
  NATIVE_METHOD(System, arraycopyBooleanUnchecked, "!([ZI[ZII)V"),
  NATIVE_METHOD(System, identityHashCode, "!(Ljava/lang/Object;)I"),
};

void register_java_lang_System(JNIEnv* env) {
  REGISTER_NATIVE_METHODS("java/lang/System");
}

}  // namespace art
<|endoftext|>