<commit_before>// This code is based on Sabberstone project.
// Copyright (c) 2017-2019 SabberStone Team, darkfriend77 & rnilva
// RosettaStone is hearthstone simulator using C++ with reinforcement learning.
// Copyright (c) 2019 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

#include <Rosetta/Cards/Cards.hpp>
#include <Rosetta/Enchants/Aura.hpp>
#include <Rosetta/Games/Game.hpp>
#include <Rosetta/Models/Battlefield.hpp>
#include <Rosetta/Models/Player.hpp>

#include <algorithm>

namespace RosettaStone
{
Aura::Aura(std::string&& enchantmentID, AuraType type)
    : m_enchantmentID(enchantmentID), m_type(type)
{
    // Do nothing
}

Aura::Aura(Aura& prototype, Entity& owner)
    : m_enchantmentID(prototype.m_enchantmentID),
      m_type(prototype.m_type),
      m_owner(&owner),
      m_effects(prototype.m_effects),
      m_turnOn(prototype.m_turnOn)
{
    // Do nothing
}

void Aura::SetToBeUpdated(bool value)
{
    m_toBeUpdated = value;
}

void Aura::Activate(Entity& owner)
{
    if (m_effects.empty())
    {
        Card card = Cards::FindCardByID(m_enchantmentID);
        m_effects = card.power.GetEnchant().value().effects;
    }

    Aura* instance = new Aura(*this, owner);

    owner.owner->GetGame()->auras.emplace_back(instance);
    owner.onGoingEffect = instance;

    instance->AddToField();
}

void Aura::Update()
{
    if (!m_toBeUpdated)
    {
        return;
    }

    UpdateInternal();
}

void Aura::Remove()
{
    m_turnOn = false;
    m_toBeUpdated = true;
    m_owner->onGoingEffect = nullptr;
}

void Aura::RemoveEntity(Entity& entity)
{
    if (&entity == m_owner)
    {
        Remove();
    }
    else
    {
        if (m_appliedEntities.empty())
        {
            return;
        }
        const auto iter = std::find(m_appliedEntities.cbegin(),
                                    m_appliedEntities.cend(), &entity);
        if (iter != m_appliedEntities.end())
        {
            m_appliedEntities.erase(iter);
        }
    }
}

void Aura::Apply(Entity& entity)
{
    auto iter =
        std::find(m_appliedEntities.begin(), m_appliedEntities.end(), &entity);
    if (iter != m_appliedEntities.end())
    {
        for (auto& effect : m_effects)
        {
            effect.Remove(*entity.auraEffects);
        }

        m_appliedEntities.erase(iter);
    }

    for (auto& effect : m_effects)
    {
        effect.Apply(*entity.auraEffects);
    }

    m_appliedEntities.emplace_back(&entity);
}

void Aura::AddToField()
{
    switch (m_type)
    {
        case AuraType::ADJACENT:
        case AuraType::FIELD_EXCEPT_SOURCE:
            m_owner->owner->GetField().auras.emplace_back(this);
            break;
        default:
            throw std::invalid_argument(
                "Aura::AddToField() - Invalid aura type!");
    }
}

void Aura::UpdateInternal()
{
    if (m_turnOn)
    {
        switch (m_type)
        {
            case AuraType::ADJACENT:
            {
                auto minion = dynamic_cast<Minion*>(m_owner);
                auto& field = m_owner->owner->GetField();
                int pos =
                    static_cast<int>(field.FindMinionPos(*minion).value());

                const int entitySize =
                    static_cast<int>(m_appliedEntities.size());
                for (int i = entitySize - 1; i >= 0; --i)
                {
                    Entity* entity = m_appliedEntities[i];
                    int fieldPos = static_cast<int>(
                        field.FindMinionPos(*dynamic_cast<Minion*>(entity))
                            .value());

                    if (std::abs(pos - fieldPos) == 1)
                    {
                        continue;
                    }

                    for (auto& effect : m_effects)
                    {
                        effect.Remove(*entity->auraEffects);
                    }

                    auto iter = std::find(m_appliedEntities.begin(),
                                          m_appliedEntities.end(), entity);
                    if (iter != m_appliedEntities.end())
                    {
                        m_appliedEntities.erase(iter);
                    }
                }

                if (pos > 0)
                {
                    auto leftMinion = field.GetMinion(pos - 1);
                    if (leftMinion != nullptr)
                    {
                        Apply(*leftMinion);
                    }
                }
                if (pos < FIELD_SIZE - 1)
                {
                    auto rightMinion = field.GetMinion(pos + 1);
                    if (rightMinion != nullptr)
                    {
                        Apply(*rightMinion);
                    }
                }

                break;
            }
            case AuraType::FIELD_EXCEPT_SOURCE:
            {
                for (auto& minion : m_owner->owner->GetField().GetAllMinions())
                {
                    if (minion != m_owner)
                    {
                        Apply(*minion);
                    }
                }
                break;
            }
            default:
                throw std::invalid_argument(
                    "Aura::UpdateInternal() - Invalid aura type!");
        }

        m_toBeUpdated = false;
    }
    else
    {
        RemoveInternal();
    }
}

void Aura::RemoveInternal()
{
    switch (m_type)
    {
        case AuraType::ADJACENT:
        case AuraType::FIELD_EXCEPT_SOURCE:
        {
            auto auras = m_owner->owner->GetField().auras;
            const auto iter = std::find(auras.begin(), auras.end(), this);
            auras.erase(iter);
            break;
        }
        default:
            throw std::invalid_argument(
                "Aura::RemoveInternal() - Invalid aura type!");
    }

    for (auto& entity : m_appliedEntities)
    {
        for (auto& effect : m_effects)
        {
            effect.Remove(*entity->auraEffects);
        }
    }

    auto auras = m_owner->owner->GetGame()->auras;
    const auto iter = std::find(auras.begin(), auras.end(), this);
    auras.erase(iter);
}
}  // namespace RosettaStone
<commit_msg>fix: Correct signed/unsigned compare warning and add 'const' keyword<commit_after>// This code is based on Sabberstone project.
// Copyright (c) 2017-2019 SabberStone Team, darkfriend77 & rnilva
// RosettaStone is hearthstone simulator using C++ with reinforcement learning.
// Copyright (c) 2019 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

#include <Rosetta/Cards/Cards.hpp>
#include <Rosetta/Enchants/Aura.hpp>
#include <Rosetta/Games/Game.hpp>
#include <Rosetta/Models/Battlefield.hpp>
#include <Rosetta/Models/Player.hpp>

#include <algorithm>

namespace RosettaStone
{
Aura::Aura(std::string&& enchantmentID, AuraType type)
    : m_enchantmentID(enchantmentID), m_type(type)
{
    // Do nothing
}

Aura::Aura(Aura& prototype, Entity& owner)
    : m_enchantmentID(prototype.m_enchantmentID),
      m_type(prototype.m_type),
      m_owner(&owner),
      m_effects(prototype.m_effects),
      m_turnOn(prototype.m_turnOn)
{
    // Do nothing
}

void Aura::SetToBeUpdated(bool value)
{
    m_toBeUpdated = value;
}

void Aura::Activate(Entity& owner)
{
    if (m_effects.empty())
    {
        Card card = Cards::FindCardByID(m_enchantmentID);
        m_effects = card.power.GetEnchant().value().effects;
    }

    Aura* instance = new Aura(*this, owner);

    owner.owner->GetGame()->auras.emplace_back(instance);
    owner.onGoingEffect = instance;

    instance->AddToField();
}

void Aura::Update()
{
    if (!m_toBeUpdated)
    {
        return;
    }

    UpdateInternal();
}

void Aura::Remove()
{
    m_turnOn = false;
    m_toBeUpdated = true;
    m_owner->onGoingEffect = nullptr;
}

void Aura::RemoveEntity(Entity& entity)
{
    if (&entity == m_owner)
    {
        Remove();
    }
    else
    {
        if (m_appliedEntities.empty())
        {
            return;
        }
        const auto iter = std::find(m_appliedEntities.cbegin(),
                                    m_appliedEntities.cend(), &entity);
        if (iter != m_appliedEntities.end())
        {
            m_appliedEntities.erase(iter);
        }
    }
}

void Aura::Apply(Entity& entity)
{
    const auto iter =
        std::find(m_appliedEntities.begin(), m_appliedEntities.end(), &entity);
    if (iter != m_appliedEntities.end())
    {
        for (auto& effect : m_effects)
        {
            effect.Remove(*entity.auraEffects);
        }

        m_appliedEntities.erase(iter);
    }

    for (auto& effect : m_effects)
    {
        effect.Apply(*entity.auraEffects);
    }

    m_appliedEntities.emplace_back(&entity);
}

void Aura::AddToField()
{
    switch (m_type)
    {
        case AuraType::ADJACENT:
        case AuraType::FIELD_EXCEPT_SOURCE:
            m_owner->owner->GetField().auras.emplace_back(this);
            break;
        default:
            throw std::invalid_argument(
                "Aura::AddToField() - Invalid aura type!");
    }
}

void Aura::UpdateInternal()
{
    if (m_turnOn)
    {
        switch (m_type)
        {
            case AuraType::ADJACENT:
            {
                const auto minion = dynamic_cast<Minion*>(m_owner);
                auto& field = m_owner->owner->GetField();
                const int pos =
                    static_cast<int>(field.FindMinionPos(*minion).value());

                const int entitySize =
                    static_cast<int>(m_appliedEntities.size());
                for (int i = entitySize - 1; i >= 0; --i)
                {
                    Entity* entity = m_appliedEntities[i];
                    const int fieldPos = static_cast<int>(
                        field.FindMinionPos(*dynamic_cast<Minion*>(entity))
                            .value());

                    if (std::abs(pos - fieldPos) == 1)
                    {
                        continue;
                    }

                    for (auto& effect : m_effects)
                    {
                        effect.Remove(*entity->auraEffects);
                    }

                    auto iter = std::find(m_appliedEntities.begin(),
                                          m_appliedEntities.end(), entity);
                    if (iter != m_appliedEntities.end())
                    {
                        m_appliedEntities.erase(iter);
                    }
                }

                if (pos > 0)
                {
                    const auto leftMinion = field.GetMinion(pos - 1);
                    if (leftMinion != nullptr)
                    {
                        Apply(*leftMinion);
                    }
                }
                if (pos < static_cast<int>(FIELD_SIZE - 1))
                {
                    const auto rightMinion = field.GetMinion(pos + 1);
                    if (rightMinion != nullptr)
                    {
                        Apply(*rightMinion);
                    }
                }

                break;
            }
            case AuraType::FIELD_EXCEPT_SOURCE:
            {
                for (auto& minion : m_owner->owner->GetField().GetAllMinions())
                {
                    if (minion != m_owner)
                    {
                        Apply(*minion);
                    }
                }
                break;
            }
            default:
                throw std::invalid_argument(
                    "Aura::UpdateInternal() - Invalid aura type!");
        }

        m_toBeUpdated = false;
    }
    else
    {
        RemoveInternal();
    }
}

void Aura::RemoveInternal()
{
    switch (m_type)
    {
        case AuraType::ADJACENT:
        case AuraType::FIELD_EXCEPT_SOURCE:
        {
            auto auras = m_owner->owner->GetField().auras;
            const auto iter = std::find(auras.begin(), auras.end(), this);
            auras.erase(iter);
            break;
        }
        default:
            throw std::invalid_argument(
                "Aura::RemoveInternal() - Invalid aura type!");
    }

    for (auto& entity : m_appliedEntities)
    {
        for (auto& effect : m_effects)
        {
            effect.Remove(*entity->auraEffects);
        }
    }

    auto auras = m_owner->owner->GetGame()->auras;
    const auto iter = std::find(auras.begin(), auras.end(), this);
    auras.erase(iter);
}
}  // namespace RosettaStone
<|endoftext|>


<commit_before>#pragma once

#include <microscopes/common/runtime_type.hpp>
#include <microscopes/common/runtime_value.hpp>
#include <microscopes/common/macros.hpp>

#include <algorithm>
#include <iterator>
#include <memory>

namespace microscopes {
namespace common {
namespace sparse_ndarray {

class dataview {
public:

  typedef std::pair<std::vector<size_t>, value_accessor> value_with_position_t;

  class slice_iterator_impl {
  public:
    virtual ~slice_iterator_impl() {}
    virtual std::unique_ptr<slice_iterator_impl> clone() const = 0;
    virtual bool equals(const slice_iterator_impl &) const = 0;
    virtual bool end() const = 0;
    virtual void next() = 0;
    virtual const value_with_position_t & value() const = 0;
  };

  class slice_iterator :
    public std::iterator<std::input_iterator_tag, const value_with_position_t>
  {
  public:
    slice_iterator() : impl_() {}
    slice_iterator(std::unique_ptr<slice_iterator_impl> &&impl)
      : impl_(std::move(impl)) {}
    slice_iterator(const slice_iterator &that)
      : impl_(that.impl_->clone()) {}
    slice_iterator(slice_iterator &&that)
      : impl_(std::move(that.impl_)) {}

    inline slice_iterator &
    operator=(const slice_iterator &that)
    {
      impl_ = std::move(that.impl_->clone());
      return *this;
    }

    inline bool
    operator==(const slice_iterator &that) const
    {
      return impl_->equals(*that.impl_);
    }

    inline bool
    operator!=(const slice_iterator &that) const
    {
      return !operator==(that);
    }

    inline slice_iterator &
    operator++()
    {
      impl_->next(); return *this;
    }

    inline slice_iterator
    operator++(int)
    {
      slice_iterator tmp(*this);
      ++(*this);
      return tmp;
    }

    inline const value_with_position_t &
    operator*() const
    {
      return impl_->value();
    }

    inline const value_with_position_t *
    operator->() const
    {
      return &impl_->value();
    }

  private:
    std::unique_ptr<slice_iterator_impl> impl_;
  };

  class slice_iterable {
  public:
    slice_iterable() : begin_(), end_() {}
    slice_iterable(const slice_iterator &begin,
                   const slice_iterator &end)
      : begin_(begin),
        end_(end) {}
    slice_iterable(slice_iterator &&begin,
                   slice_iterator &&end)
      : begin_(std::move(begin)),
        end_(std::move(end)) {}

    inline slice_iterator begin() const { return begin_; }
    inline slice_iterator end() const { return end_; }

  private:
    slice_iterator begin_;
    slice_iterator end_;
  };

  dataview(const std::vector<size_t> &shape, const runtime_type &type)
    : shape_(shape), type_(type)
  {
    // assume no zero-dimesional things
    MICROSCOPES_DCHECK(shape_.size(), "zero-d array not allowed");
    for (auto s : shape)
      MICROSCOPES_DCHECK(s, "empty-dimesion not allowed");
  }

  inline size_t dims() const { return shape_.size(); }
  inline const std::vector<size_t> & shape() const { return shape_; }
  inline const runtime_type & type() const { return type_; }

  virtual value_accessor get(const std::vector<size_t> &indices) const = 0;

  virtual slice_iterable slice(size_t dim, size_t idx) const = 0;

protected:
  std::vector<size_t> shape_;
  runtime_type type_;
};

namespace detail {

class product {
public:

  enum tag_t { SINGLETON, RANGE, };

  struct indices {
    indices() : tag_(), v_() {}
    indices(tag_t tag, size_t v)
      : tag_(tag), v_(v) {}
    tag_t tag_;
    size_t v_;
  };

  product(const std::vector<indices> &is)
    : is_(is)
  {
    cur_.resize(is.size());
    reset();
  }

  inline void
  reset()
  {
    end_ = true;
    pos_ = 0;
    for (size_t i = 0; i < is_.size(); i++) {
      end_ = false;
      if (is_[i].tag_ == SINGLETON) {
        cur_[i] = is_[i].v_;
      } else {
        MICROSCOPES_ASSERT(is_[i].tag_ == RANGE);
        MICROSCOPES_ASSERT(is_[i].v_);
        cur_[i] = 0;
      }
    }
  }

  inline void
  setEnd()
  {
    end_ = true;
    pos_ = 1;
    for (size_t i = 0; i < is_.size(); i++) {
      if (is_[i].tag_ == SINGLETON) {
        cur_[i] = is_[i].v_;
      } else {
        cur_[i] = 0;
        pos_ *= is_[i].v_;
      }
    }
  }

  inline bool
  end() const
  {
    return end_;
  }

  inline size_t
  pos() const
  {
    return pos_;
  }

  inline const std::vector<size_t> &
  value() const
  {
    MICROSCOPES_ASSERT(!end());
    return cur_;
  }

  inline void
  next()
  {
    MICROSCOPES_ASSERT(!end_);
    for (ssize_t i = is_.size() - 1; i >= 0; i--) {
      if (is_[i].tag_ == SINGLETON)
        continue;
      if ((cur_[i]+1) < is_[i].v_) {
        cur_[i]++;
        pos_++;
        return;
      }
      cur_[i] = 0;
    }
    end_ = true;
    pos_++;
  }

private:
  std::vector<indices> is_;
  std::vector<size_t> cur_;
  size_t pos_;
  bool end_;
};

} // namespace detail

/**
 * useful for testing, but horrible in performance
 */
class row_major_dense_dataview : public dataview {
public:
  row_major_dense_dataview(const uint8_t *data,
                           const bool *mask,
                           const std::vector<size_t> &shape,
                           const runtime_type &type)
    : dataview(shape, type), data_(data), mask_(mask),
      stepsize_(runtime_type_traits::RuntimeTypeSize(type))
  {
    MICROSCOPES_DCHECK(data, "data cannot be null");
    multipliers_.push_back(1);
    auto rit = shape.rbegin();
    for (size_t i = 0; i < shape.size() - 1; ++i, ++rit)
      multipliers_.push_back(multipliers_.back() * (*rit));
    std::reverse(multipliers_.begin(), multipliers_.end());
  }

  value_accessor
  get(const std::vector<size_t> &indices) const override
  {
    MICROSCOPES_DCHECK(dims() == indices.size(), "invalid # of indices");
    for (size_t i = 0; i < dims(); i++)
      MICROSCOPES_DCHECK(indices[i] < shape_[i], "index out of bounds");
    return accessor(indices);
  }

  class slice_iterator_impl : public dataview::slice_iterator_impl {
    friend class row_major_dense_dataview;
  protected:
    slice_iterator_impl(
      const row_major_dense_dataview *px,
      size_t dim,
      size_t idx,
      const detail::product &iter)
      : px_(px), dim_(dim), idx_(idx), iter_(iter) {}

  public:
    std::unique_ptr<dataview::slice_iterator_impl>
    clone() const override
    {
      return std::unique_ptr<slice_iterator_impl>(new slice_iterator_impl(*this));
    }

    bool
    equals(const dataview::slice_iterator_impl &that) const override
    {
      const auto &o = static_cast<const slice_iterator_impl &>(that);
      return px_ == o.px_ &&
             dim_ == o.dim_ &&
             idx_ == o.idx_ &&
             iter_.pos() == o.iter_.pos();
    }

    bool end() const override { return iter_.end(); }

    void next() override { iter_.next(); }

    const value_with_position_t &
    value() const override
    {
      // XXX: const_cast so we can mutate the storage
      const_cast<slice_iterator_impl *>(this)->storage_.first = iter_.value();
      const_cast<slice_iterator_impl *>(this)->storage_.second = px_->accessor(iter_.value());
      return storage_;
    }

  private:
    const row_major_dense_dataview *px_;
    size_t dim_;
    size_t idx_;
    detail::product iter_;
    value_with_position_t storage_;
  };

  slice_iterable
  slice(size_t dim, size_t idx) const override
  {
    MICROSCOPES_DCHECK(dim < dims(), "invalid dimension");
    MICROSCOPES_DCHECK(idx < shape_[dim], "invalid index");
    std::vector<detail::product::indices> is(dims());
    for (size_t i = 0; i < dims(); i++) {
      if (i == dim)
        is[i] = detail::product::indices(detail::product::SINGLETON, idx);
      else
        is[i] = detail::product::indices(detail::product::RANGE, shape_[i]);
    }

    detail::product begin_iter(is), end_iter(is);
    end_iter.setEnd();

    std::unique_ptr<dataview::slice_iterator_impl> begin(
        new slice_iterator_impl(
          this,
          dim,
          idx,
          begin_iter));

    std::unique_ptr<dataview::slice_iterator_impl> end(
        new slice_iterator_impl(
          this,
          dim,
          idx,
          end_iter));

    return std::move(
        slice_iterable(std::move(begin), std::move(end)));
  }

private:

  inline value_accessor
  accessor(const std::vector<size_t> &indices) const
  {
    const size_t off = offset(indices);
    return value_accessor(
        data_ + stepsize_ * off,
        mask_ ? (mask_ + off) : nullptr,
        type());
  }

  inline size_t
  offset(const std::vector<size_t> &indices) const
  {
    MICROSCOPES_ASSERT(indices.size() == dims());
    size_t off = 0;
    for (size_t i = 0; i < dims(); i++)
      off += indices[i] * multipliers_[i];
    return off;
  }

  const uint8_t *data_;
  const bool *mask_;
  size_t stepsize_;
  std::vector<size_t> multipliers_;
};

} // namespace sparse_ndarray
} // namespace common
} // namespace microscopes
<commit_msg>fix iterator<commit_after>#pragma once

#include <microscopes/common/runtime_type.hpp>
#include <microscopes/common/runtime_value.hpp>
#include <microscopes/common/macros.hpp>

#include <algorithm>
#include <iterator>
#include <memory>

namespace microscopes {
namespace common {
namespace sparse_ndarray {

class dataview {
public:

  typedef std::pair<std::vector<size_t>, value_accessor> value_with_position_t;

  class slice_iterator_impl {
  public:
    virtual ~slice_iterator_impl() {}
    virtual std::unique_ptr<slice_iterator_impl> clone() const = 0;
    virtual bool equals(const slice_iterator_impl &) const = 0;
    virtual bool end() const = 0;
    virtual void next() = 0;
    virtual const value_with_position_t & value() const = 0;
  };

  class slice_iterator :
    public std::iterator<std::input_iterator_tag, const value_with_position_t>
  {
  public:
    slice_iterator() : impl_() {}
    slice_iterator(std::unique_ptr<slice_iterator_impl> &&impl)
      : impl_(std::move(impl)) {}
    slice_iterator(const slice_iterator &that)
      : impl_(that.impl_->clone()) {}
    slice_iterator(slice_iterator &&that)
      : impl_(std::move(that.impl_)) {}

    inline slice_iterator &
    operator=(const slice_iterator &that)
    {
      impl_ = std::move(that.impl_->clone());
      return *this;
    }

    inline bool
    operator==(const slice_iterator &that) const
    {
      return impl_->equals(*that.impl_);
    }

    inline bool
    operator!=(const slice_iterator &that) const
    {
      return !operator==(that);
    }

    inline slice_iterator &
    operator++()
    {
      impl_->next(); return *this;
    }

    inline slice_iterator
    operator++(int)
    {
      slice_iterator tmp(*this);
      ++(*this);
      return tmp;
    }

    inline const value_with_position_t &
    operator*() const
    {
      return impl_->value();
    }

    inline const value_with_position_t *
    operator->() const
    {
      return &impl_->value();
    }

  private:
    std::unique_ptr<slice_iterator_impl> impl_;
  };

  class slice_iterable {
  public:
    slice_iterable() : begin_(), end_() {}
    slice_iterable(const slice_iterator &begin,
                   const slice_iterator &end)
      : begin_(begin),
        end_(end) {}
    slice_iterable(slice_iterator &&begin,
                   slice_iterator &&end)
      : begin_(std::move(begin)),
        end_(std::move(end)) {}

    inline slice_iterator begin() const { return begin_; }
    inline slice_iterator end() const { return end_; }

  private:
    slice_iterator begin_;
    slice_iterator end_;
  };

  dataview(const std::vector<size_t> &shape, const runtime_type &type)
    : shape_(shape), type_(type)
  {
    // assume no zero-dimesional things
    MICROSCOPES_DCHECK(shape_.size(), "zero-d array not allowed");
    for (auto s : shape)
      MICROSCOPES_DCHECK(s, "empty-dimesion not allowed");
  }

  virtual ~dataview() {}

  inline size_t dims() const { return shape_.size(); }
  inline const std::vector<size_t> & shape() const { return shape_; }
  inline const runtime_type & type() const { return type_; }

  virtual value_accessor get(const std::vector<size_t> &indices) const = 0;

  virtual slice_iterable slice(size_t dim, size_t idx) const = 0;

protected:
  std::vector<size_t> shape_;
  runtime_type type_;
};

namespace detail {

class product {
public:

  enum tag_t { SINGLETON, RANGE, };

  struct indices {
    indices() : tag_(), v_() {}
    indices(tag_t tag, size_t v)
      : tag_(tag), v_(v) {}
    tag_t tag_;
    size_t v_;
  };

  product(const std::vector<indices> &is)
    : is_(is)
  {
    cur_.resize(is.size());
    reset();
  }

  inline void
  reset()
  {
    end_ = true;
    pos_ = 0;
    for (size_t i = 0; i < is_.size(); i++) {
      end_ = false;
      if (is_[i].tag_ == SINGLETON) {
        cur_[i] = is_[i].v_;
      } else {
        MICROSCOPES_ASSERT(is_[i].tag_ == RANGE);
        MICROSCOPES_ASSERT(is_[i].v_);
        cur_[i] = 0;
      }
    }
  }

  inline void
  setEnd()
  {
    end_ = true;
    pos_ = 1;
    for (size_t i = 0; i < is_.size(); i++) {
      if (is_[i].tag_ == SINGLETON) {
        cur_[i] = is_[i].v_;
      } else {
        cur_[i] = 0;
        pos_ *= is_[i].v_;
      }
    }
  }

  inline bool
  end() const
  {
    return end_;
  }

  inline size_t
  pos() const
  {
    return pos_;
  }

  inline const std::vector<size_t> &
  value() const
  {
    MICROSCOPES_ASSERT(!end());
    return cur_;
  }

  inline void
  next()
  {
    MICROSCOPES_ASSERT(!end_);
    for (ssize_t i = is_.size() - 1; i >= 0; i--) {
      if (is_[i].tag_ == SINGLETON)
        continue;
      if ((cur_[i]+1) < is_[i].v_) {
        cur_[i]++;
        pos_++;
        return;
      }
      cur_[i] = 0;
    }
    end_ = true;
    pos_++;
  }

private:
  std::vector<indices> is_;
  std::vector<size_t> cur_;
  size_t pos_;
  bool end_;
};

} // namespace detail

/**
 * useful for testing, but horrible in performance
 */
class row_major_dense_dataview : public dataview {
public:
  row_major_dense_dataview(const uint8_t *data,
                           const bool *mask,
                           const std::vector<size_t> &shape,
                           const runtime_type &type)
    : dataview(shape, type), data_(data), mask_(mask),
      stepsize_(runtime_type_traits::RuntimeTypeSize(type))
  {
    MICROSCOPES_DCHECK(data, "data cannot be null");
    multipliers_.push_back(1);
    auto rit = shape.rbegin();
    for (size_t i = 0; i < shape.size() - 1; ++i, ++rit)
      multipliers_.push_back(multipliers_.back() * (*rit));
    std::reverse(multipliers_.begin(), multipliers_.end());
  }

  value_accessor
  get(const std::vector<size_t> &indices) const override
  {
    MICROSCOPES_DCHECK(dims() == indices.size(), "invalid # of indices");
    for (size_t i = 0; i < dims(); i++)
      MICROSCOPES_DCHECK(indices[i] < shape_[i], "index out of bounds");
    return accessor(indices);
  }

  class slice_iterator_impl : public dataview::slice_iterator_impl {
    friend class row_major_dense_dataview;
  protected:
    slice_iterator_impl(
      const row_major_dense_dataview *px,
      size_t dim,
      size_t idx,
      const detail::product &iter)
      : px_(px), dim_(dim), idx_(idx), iter_(iter)
    {
      for (;;) {
        if (iter_.end() || !px->accessor(iter_.value()).anymasked())
          break;
        iter_.next();
      }
    }

  public:
    std::unique_ptr<dataview::slice_iterator_impl>
    clone() const override
    {
      return std::unique_ptr<slice_iterator_impl>(new slice_iterator_impl(*this));
    }

    bool
    equals(const dataview::slice_iterator_impl &that) const override
    {
      const auto &o = static_cast<const slice_iterator_impl &>(that);
      return px_ == o.px_ &&
             dim_ == o.dim_ &&
             idx_ == o.idx_ &&
             iter_.pos() == o.iter_.pos();
    }

    bool end() const override { return iter_.end(); }

    void
    next() override
    {
      for (;;) {
        iter_.next();
        if (iter_.end() || !px_->accessor(iter_.value()).anymasked())
          break;
      }
    }

    const value_with_position_t &
    value() const override
    {
      // XXX: const_cast so we can mutate the storage
      const_cast<slice_iterator_impl *>(this)->storage_.first = iter_.value();
      const_cast<slice_iterator_impl *>(this)->storage_.second = px_->accessor(iter_.value());
      return storage_;
    }

  private:
    const row_major_dense_dataview *px_;
    size_t dim_;
    size_t idx_;
    detail::product iter_;
    value_with_position_t storage_;
  };

  slice_iterable
  slice(size_t dim, size_t idx) const override
  {
    MICROSCOPES_DCHECK(dim < dims(), "invalid dimension");
    MICROSCOPES_DCHECK(idx < shape_[dim], "invalid index");
    std::vector<detail::product::indices> is(dims());
    for (size_t i = 0; i < dims(); i++) {
      if (i == dim)
        is[i] = detail::product::indices(detail::product::SINGLETON, idx);
      else
        is[i] = detail::product::indices(detail::product::RANGE, shape_[i]);
    }

    detail::product begin_iter(is), end_iter(is);
    end_iter.setEnd();

    std::unique_ptr<dataview::slice_iterator_impl> begin(
        new slice_iterator_impl(
          this,
          dim,
          idx,
          begin_iter));

    std::unique_ptr<dataview::slice_iterator_impl> end(
        new slice_iterator_impl(
          this,
          dim,
          idx,
          end_iter));

    return std::move(
        slice_iterable(std::move(begin), std::move(end)));
  }

private:

  inline value_accessor
  accessor(const std::vector<size_t> &indices) const
  {
    const size_t off = offset(indices);
    return value_accessor(
        data_ + stepsize_ * off,
        mask_ ? (mask_ + off) : nullptr,
        type());
  }

  inline size_t
  offset(const std::vector<size_t> &indices) const
  {
    MICROSCOPES_ASSERT(indices.size() == dims());
    size_t off = 0;
    for (size_t i = 0; i < dims(); i++)
      off += indices[i] * multipliers_[i];
    return off;
  }

  const uint8_t *data_;
  const bool *mask_;
  size_t stepsize_;
  std::vector<size_t> multipliers_;
};

} // namespace sparse_ndarray
} // namespace common
} // namespace microscopes
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2015, NVIDIA CORPORATION
 * Copyright (c) 2015, Nuno Subtil <subtil@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the name of the copyright holders nor the names of its
 *      contributors may be used to endorse or promote products derived from
 *      this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include <iterator>

#include <tbb/parallel_reduce.h>
#include <tbb/blocked_range.h>

namespace lift {

namespace __lift_tbb_reduction {

// below this many elements we prefer to do summation sequentially
constexpr uint32 sum_sequential_threshold = 10000;

template <typename InputIterator>
struct sum_operator
{
    typedef typename std::iterator_traits<InputIterator>::value_type value_type;
    value_type value;

    sum_operator()
        : value(0)
    { }

    sum_operator(sum_operator&, tbb::split)
        : value(0)
    { }

    void operator() (const tbb::blocked_range<InputIterator>& r)
    {
        value_type temp = value;
        for(InputIterator a = r.begin(); a != r.end(); a++)
        {
            temp += *a;
        }

        value = temp;
    }

    void join(sum_operator& rhs)
    {
        value += rhs.value;
    }
};

} // namespace __lift_tbb_reduction

template <>
template <typename InputIterator>
inline auto parallel<host>::sum(InputIterator first,
                                size_t len,
                                allocation<host, uint8>& temp_storage) -> typename std::iterator_traits<InputIterator>::value_type
{
    typedef typename std::iterator_traits<InputIterator>::value_type value_type;

    if (len < __lift_tbb_reduction::sum_sequential_threshold || true)
    {
        value_type v = 0;
        for(auto i = first; i < first + len; i++)
        {
            v += *i;
        }

        return v;
    } else {
        __lift_tbb_reduction::sum_operator<InputIterator> sum;
        tbb::parallel_reduce(tbb::blocked_range<InputIterator>(first, first + len), sum);
        return sum.value;
    }
}

template <>
template <typename InputIterator>
inline auto parallel<host>::sum(InputIterator first,
                                size_t len,
                                vector<host, uint8>& temp_storage) -> typename std::iterator_traits<InputIterator>::value_type
{
    typedef typename std::iterator_traits<InputIterator>::value_type value_type;

    if (len < __lift_tbb_reduction::sum_sequential_threshold || true)
    {
        value_type v = 0;
        for(auto i = first; i < first + len; i++)
        {
            v += *i;
        }

        return v;
    } else {
        __lift_tbb_reduction::sum_operator<InputIterator> sum;
        tbb::parallel_reduce(tbb::blocked_range<InputIterator>(first, first + len), sum);
        return sum.value;
    }
}

} // namespace lift
<commit_msg>parallel/tbb: Refactor parallel sum, add sequential path<commit_after>/*
 * Copyright (c) 2014-2015, NVIDIA CORPORATION
 * Copyright (c) 2015, Nuno Subtil <subtil@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    * Neither the name of the copyright holders nor the names of its
 *      contributors may be used to endorse or promote products derived from
 *      this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include <iterator>

#include <tbb/parallel_reduce.h>
#include <tbb/blocked_range.h>

namespace lift {

namespace __lift_tbb_reduction {

template <typename T>
struct parameters
{
    static constexpr uint32 sequential_threshold = 500000;
};

template <>
struct parameters<float>
{
    static constexpr uint32 sequential_threshold = 50000;
};

template <>
struct parameters<double>
{
    static constexpr uint32 sequential_threshold = 50000;
};

template <typename InputIterator, typename reduction_operator>
inline auto parallel_reduction(InputIterator first,
                               size_t len,
                               const typename std::iterator_traits<InputIterator>::value_type& initial_value,
                               reduction_operator reduction_op)
    -> typename std::iterator_traits<InputIterator>::value_type
{
    typedef typename std::iterator_traits<InputIterator>::value_type value_type;

    // applies op sequentially across a tbb blocked_range
    // used as the range reduction operator for parallel_reduce
    auto range_reduction_operator =
            [&](const tbb::blocked_range<InputIterator>& range, const value_type& initial_value) -> value_type
            {
                value_type value = initial_value;

                for(value_type v : range)
                {
                    value = reduction_op(value, v);
                }

                return value;
            };

    return tbb::parallel_reduce(tbb::blocked_range<InputIterator>(first, first + len),
                                initial_value,
                                range_reduction_operator,
                                reduction_op);
}

template <typename InputIterator, typename reduction_operator>
inline auto sequential_reduction(InputIterator first,
                                 size_t len,
                                 const typename std::iterator_traits<InputIterator>::value_type& initial_value,
                                 reduction_operator op)
    -> typename std::iterator_traits<InputIterator>::value_type
{
    typedef typename std::iterator_traits<InputIterator>::value_type value_type;

    value_type ret = initial_value;
    for(size_t i = 0; i < len; i++)
    {
        ret = op(ret, *(first + i));
    }

    return ret;
}

} // namespace __lift_tbb_reduction

template <>
template <typename InputIterator>
inline auto parallel<host>::sum(InputIterator first,
                                size_t len,
                                allocation<host, uint8>& temp_storage) -> typename std::iterator_traits<InputIterator>::value_type
{
    typedef typename std::iterator_traits<InputIterator>::value_type value_type;

    auto sum_operator =
            [] (const value_type& a, const value_type& b) -> value_type
            {
                return a + b;
            };

    if (len <= __lift_tbb_reduction::parameters<value_type>::sequential_threshold)
    {
        return __lift_tbb_reduction::sequential_reduction(first, len, 0, sum_operator);
    } else {
        return __lift_tbb_reduction::parallel_reduction(first, len, 0, sum_operator);
    }
}

template <>
template <typename InputIterator>
inline auto parallel<host>::sum(InputIterator first,
                                size_t len,
                                vector<host, uint8>& temp_storage) -> typename std::iterator_traits<InputIterator>::value_type
{
    typedef typename std::iterator_traits<InputIterator>::value_type value_type;

    auto sum_operator =
            [] (const value_type& a, const value_type& b) -> value_type
            {
                return a + b;
            };

    if (len <= __lift_tbb_reduction::parameters<value_type>::sequential_threshold)
    {
        return __lift_tbb_reduction::sequential_reduction(first, len, 0, sum_operator);
    } else {
        return __lift_tbb_reduction::parallel_reduction(first, len, 0, sum_operator);
    }
}

} // namespace lift
<|endoftext|>


<commit_before>#pragma once

#include "elog_block.hpp"
#include "elog_entry.hpp"
#include "xyz/openbmc_project/Collection/DeleteAll/server.hpp"
#include "xyz/openbmc_project/Logging/Create/server.hpp"
#include "xyz/openbmc_project/Logging/Entry/server.hpp"
#include "xyz/openbmc_project/Logging/Internal/Manager/server.hpp"

#include <list>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>

namespace phosphor
{
namespace logging
{

extern const std::map<std::string, std::vector<std::string>> g_errMetaMap;
extern const std::map<std::string, level> g_errLevelMap;

using CreateIface = sdbusplus::xyz::openbmc_project::Logging::server::Create;
using DeleteAllIface =
    sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll;

namespace details
{
template <typename... T>
using ServerObject = typename sdbusplus::server::object::object<T...>;

using ManagerIface =
    sdbusplus::xyz::openbmc_project::Logging::Internal::server::Manager;

} // namespace details

constexpr size_t ffdcFormatPos = 0;
constexpr size_t ffdcSubtypePos = 1;
constexpr size_t ffdcVersionPos = 2;
constexpr size_t ffdcFDPos = 3;

using FFDCEntry = std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t,
                             sdbusplus::message::unix_fd>;

using FFDCEntries = std::vector<FFDCEntry>;

namespace internal
{

/** @class Manager
 *  @brief OpenBMC logging manager implementation.
 *  @details A concrete implementation for the
 *  xyz.openbmc_project.Logging.Internal.Manager DBus API.
 */
class Manager : public details::ServerObject<details::ManagerIface>
{
  public:
    Manager() = delete;
    Manager(const Manager&) = delete;
    Manager& operator=(const Manager&) = delete;
    Manager(Manager&&) = delete;
    Manager& operator=(Manager&&) = delete;
    virtual ~Manager() = default;

    /** @brief Constructor to put object onto bus at a dbus path.
     *  @param[in] bus - Bus to attach to.
     *  @param[in] path - Path to attach at.
     */
    Manager(sdbusplus::bus::bus& bus, const char* objPath) :
        details::ServerObject<details::ManagerIface>(bus, objPath), busLog(bus),
        entryId(0), fwVersion(readFWVersion()){};

    /*
     * @fn commit()
     * @brief sd_bus Commit method implementation callback.
     * @details Create an error/event log based on transaction id and
     *          error message.
     * @param[in] transactionId - Unique identifier of the journal entries
     *                            to be committed.
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     */
    uint32_t commit(uint64_t transactionId, std::string errMsg) override;

    /*
     * @fn commit()
     * @brief sd_bus CommitWithLvl method implementation callback.
     * @details Create an error/event log based on transaction id and
     *          error message.
     * @param[in] transactionId - Unique identifier of the journal entries
     *                            to be committed.
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] errLvl - level of the error
     */
    uint32_t commitWithLvl(uint64_t transactionId, std::string errMsg,
                           uint32_t errLvl) override;

    /** @brief Erase specified entry d-bus object
     *
     * @param[in] entryId - unique identifier of the entry
     */
    void erase(uint32_t entryId);

    /** @brief Construct error d-bus objects from their persisted
     *         representations.
     */
    void restore();

    /** @brief  Erase all error log entries
     *
     */
    void eraseAll()
    {
        auto iter = entries.begin();
        while (iter != entries.end())
        {
            auto e = iter->first;
            ++iter;
            erase(e);
        }
        entryId = 0;
    }

    /** @brief Returns the count of high severity errors
     *
     *  @return int - count of real errors
     */
    int getRealErrSize();

    /** @brief Returns the count of Info errors
     *
     *  @return int - count of info errors
     */
    int getInfoErrSize();

    /** @brief Returns the number of blocking errors
     *
     *  @return int - count of blocking errors
     */
    int getBlockingErrSize()
    {
        return blockingErrors.size();
    }

    /** @brief Returns the number of property change callback objects
     *
     *  @return int - count of property callback entries
     */
    int getEntryCallbackSize()
    {
        return propChangedEntryCallback.size();
    }

    /**
     * @brief Returns the sdbusplus bus object
     *
     * @return sdbusplus::bus::bus&
     */
    sdbusplus::bus::bus& getBus()
    {
        return busLog;
    }

    /**
     * @brief Returns the ID of the last created entry
     *
     * @return uint32_t - The ID
     */
    uint32_t lastEntryID() const
    {
        return entryId;
    }

    /** @brief Creates an event log
     *
     *  This is an alternative to the _commit() API.  It doesn't use
     *  the journal to look up event log metadata like _commit does.
     *
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] severity - level of the error
     * @param[in] additionalData - The AdditionalData property for the error
     */
    void create(
        const std::string& message,
        sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
        const std::map<std::string, std::string>& additionalData);

    /** @brief Creates an event log, and accepts FFDC files
     *
     * This is the same as create(), but also takes an FFDC argument.
     *
     * The FFDC argument is a vector of tuples that allows one to pass in file
     * descriptors for files that contain FFDC (First Failure Data Capture).
     * These will be passed to any event logging extensions.
     *
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] severity - level of the error
     * @param[in] additionalData - The AdditionalData property for the error
     * @param[in] ffdc - A vector of FFDC file info
     */
    void createWithFFDC(
        const std::string& message,
        sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
        const std::map<std::string, std::string>& additionalData,
        const FFDCEntries& ffdc);

    /** @brief Common wrapper for creating an Entry object
     *
     * @return true if quiesce on error setting is enabled, false otherwise
     */
    bool isQuiesceOnErrorEnabled();

    /** @brief Create boot block association and quiesce host if running
     *
     * @param[in] entryId - The ID of the phosphor logging error
     */
    void quiesceOnError(const uint32_t entryId);

    /** @brief Check if inventory callout present in input entry
     *
     * @param[in] entry - The error to check for callouts
     *
     * @return true if inventory item in associations, false otherwise
     */
    bool isCalloutPresent(const Entry& entry);

    /** @brief Check (and remove) entry being erased from blocking errors
     *
     * @param[in] entryId - The entry that is being erased
     */
    void checkAndRemoveBlockingError(uint32_t entryId);

    /** @brief Persistent map of Entry dbus objects and their ID */
    std::map<uint32_t, std::unique_ptr<Entry>> entries;

  private:
    /*
     * @fn _commit()
     * @brief commit() helper
     * @param[in] transactionId - Unique identifier of the journal entries
     *                            to be committed.
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] errLvl - level of the error
     */
    void _commit(uint64_t transactionId, std::string&& errMsg,
                 Entry::Level errLvl);

    /** @brief Call metadata handler(s), if any. Handlers may create
     *         associations.
     *  @param[in] errorName - name of the error
     *  @param[in] additionalData - list of metadata (in key=value format)
     *  @param[out] objects - list of error's association objects
     */
    void processMetadata(const std::string& errorName,
                         const std::vector<std::string>& additionalData,
                         AssociationList& objects) const;

    /** @brief Synchronize unwritten journal messages to disk.
     *  @details This is the same implementation as the systemd command
     *  "journalctl --sync".
     */
    void journalSync();

    /** @brief Reads the BMC code level
     *
     *  @return std::string - the version string
     */
    static std::string readFWVersion();

    /** @brief Call any create() functions provided by any extensions.
     *  This is called right after an event log is created to allow
     *  extensions to create their own log based on this one.
     *
     *  @param[in] entry - the new event log entry
     *  @param[in] ffdc - A vector of FFDC file info
     */
    void doExtensionLogCreate(const Entry& entry, const FFDCEntries& ffdc);

    /** @brief Common wrapper for creating an Entry object
     *
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] errLvl - level of the error
     * @param[in] additionalData - The AdditionalData property for the error
     * @param[in] ffdc - A vector of FFDC file info. Defaults to an empty
     * vector.
     */
    void createEntry(std::string errMsg, Entry::Level errLvl,
                     std::vector<std::string> additionalData,
                     const FFDCEntries& ffdc = FFDCEntries{});

    /** @brief Notified on entry property changes
     *
     * If an entry is blocking, this callback will be registered to monitor for
     * the entry having it's Resolved field set to true. If it is then remove
     * the blocking object.
     *
     * @param[in] msg - sdbusplus dbusmessage
     */
    void onEntryResolve(sdbusplus::message::message& msg);

    /** @brief Remove block objects for any resolved entries  */
    void findAndRemoveResolvedBlocks();

    /** @brief Quiesce host if it is running
     *
     * This is called when the user has requested the system be quiesced
     * if a log with a callout is created
     */
    void checkAndQuiesceHost();

    /** @brief Persistent sdbusplus DBus bus connection. */
    sdbusplus::bus::bus& busLog;

    /** @brief List of error ids for high severity errors */
    std::list<uint32_t> realErrors;

    /** @brief List of error ids for Info(and below) severity */
    std::list<uint32_t> infoErrors;

    /** @brief Id of last error log entry */
    uint32_t entryId;

    /** @brief The BMC firmware version */
    const std::string fwVersion;

    /** @brief Array of blocking errors */
    std::vector<std::unique_ptr<Block>> blockingErrors;

    /** @brief Map of entry id to call back object on properties changed */
    std::map<uint32_t, std::unique_ptr<sdbusplus::bus::match::match>>
        propChangedEntryCallback;
};

} // namespace internal

/** @class Manager
 *  @brief Implementation for deleting all error log entries and
 *         creating new logs.
 *  @details A concrete implementation for the
 *           xyz.openbmc_project.Collection.DeleteAll and
 *           xyz.openbmc_project.Logging.Create interfaces.
 */
class Manager : public details::ServerObject<DeleteAllIface, CreateIface>
{
  public:
    Manager() = delete;
    Manager(const Manager&) = delete;
    Manager& operator=(const Manager&) = delete;
    Manager(Manager&&) = delete;
    Manager& operator=(Manager&&) = delete;
    virtual ~Manager() = default;

    /** @brief Constructor to put object onto bus at a dbus path.
     *         Defer signal registration (pass true for deferSignal to the
     *         base class) until after the properties are set.
     *  @param[in] bus - Bus to attach to.
     *  @param[in] path - Path to attach at.
     *  @param[in] manager - Reference to internal manager object.
     */
    Manager(sdbusplus::bus::bus& bus, const std::string& path,
            internal::Manager& manager) :
        details::ServerObject<DeleteAllIface, CreateIface>(bus, path.c_str(),
                                                           true),
        manager(manager){};

    /** @brief Delete all d-bus objects.
     */
    void deleteAll()
    {
        manager.eraseAll();
    }

    /** @brief D-Bus method call implementation to create an event log.
     *
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] severity - Level of the error
     * @param[in] additionalData - The AdditionalData property for the error
     */
    void create(
        std::string message,
        sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
        std::map<std::string, std::string> additionalData) override
    {
        manager.create(message, severity, additionalData);
    }

    /** @brief D-Bus method call implementation to create an event log with FFDC
     *
     * The same as create(), but takes an extra FFDC argument.
     *
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] severity - Level of the error
     * @param[in] additionalData - The AdditionalData property for the error
     * @param[in] ffdc - A vector of FFDC file info
     */
    void createWithFFDCFiles(
        std::string message,
        sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
        std::map<std::string, std::string> additionalData,
        std::vector<std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t,
                               sdbusplus::message::unix_fd>>
            ffdc) override
    {
        manager.createWithFFDC(message, severity, additionalData, ffdc);
    }

  private:
    /** @brief This is a reference to manager object */
    internal::Manager& manager;
};

} // namespace logging
} // namespace phosphor
<commit_msg>log_manager: add override to deleteAll<commit_after>#pragma once

#include "elog_block.hpp"
#include "elog_entry.hpp"
#include "xyz/openbmc_project/Collection/DeleteAll/server.hpp"
#include "xyz/openbmc_project/Logging/Create/server.hpp"
#include "xyz/openbmc_project/Logging/Entry/server.hpp"
#include "xyz/openbmc_project/Logging/Internal/Manager/server.hpp"

#include <list>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>

namespace phosphor
{
namespace logging
{

extern const std::map<std::string, std::vector<std::string>> g_errMetaMap;
extern const std::map<std::string, level> g_errLevelMap;

using CreateIface = sdbusplus::xyz::openbmc_project::Logging::server::Create;
using DeleteAllIface =
    sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll;

namespace details
{
template <typename... T>
using ServerObject = typename sdbusplus::server::object::object<T...>;

using ManagerIface =
    sdbusplus::xyz::openbmc_project::Logging::Internal::server::Manager;

} // namespace details

constexpr size_t ffdcFormatPos = 0;
constexpr size_t ffdcSubtypePos = 1;
constexpr size_t ffdcVersionPos = 2;
constexpr size_t ffdcFDPos = 3;

using FFDCEntry = std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t,
                             sdbusplus::message::unix_fd>;

using FFDCEntries = std::vector<FFDCEntry>;

namespace internal
{

/** @class Manager
 *  @brief OpenBMC logging manager implementation.
 *  @details A concrete implementation for the
 *  xyz.openbmc_project.Logging.Internal.Manager DBus API.
 */
class Manager : public details::ServerObject<details::ManagerIface>
{
  public:
    Manager() = delete;
    Manager(const Manager&) = delete;
    Manager& operator=(const Manager&) = delete;
    Manager(Manager&&) = delete;
    Manager& operator=(Manager&&) = delete;
    virtual ~Manager() = default;

    /** @brief Constructor to put object onto bus at a dbus path.
     *  @param[in] bus - Bus to attach to.
     *  @param[in] path - Path to attach at.
     */
    Manager(sdbusplus::bus::bus& bus, const char* objPath) :
        details::ServerObject<details::ManagerIface>(bus, objPath), busLog(bus),
        entryId(0), fwVersion(readFWVersion()){};

    /*
     * @fn commit()
     * @brief sd_bus Commit method implementation callback.
     * @details Create an error/event log based on transaction id and
     *          error message.
     * @param[in] transactionId - Unique identifier of the journal entries
     *                            to be committed.
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     */
    uint32_t commit(uint64_t transactionId, std::string errMsg) override;

    /*
     * @fn commit()
     * @brief sd_bus CommitWithLvl method implementation callback.
     * @details Create an error/event log based on transaction id and
     *          error message.
     * @param[in] transactionId - Unique identifier of the journal entries
     *                            to be committed.
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] errLvl - level of the error
     */
    uint32_t commitWithLvl(uint64_t transactionId, std::string errMsg,
                           uint32_t errLvl) override;

    /** @brief Erase specified entry d-bus object
     *
     * @param[in] entryId - unique identifier of the entry
     */
    void erase(uint32_t entryId);

    /** @brief Construct error d-bus objects from their persisted
     *         representations.
     */
    void restore();

    /** @brief  Erase all error log entries
     *
     */
    void eraseAll()
    {
        auto iter = entries.begin();
        while (iter != entries.end())
        {
            auto e = iter->first;
            ++iter;
            erase(e);
        }
        entryId = 0;
    }

    /** @brief Returns the count of high severity errors
     *
     *  @return int - count of real errors
     */
    int getRealErrSize();

    /** @brief Returns the count of Info errors
     *
     *  @return int - count of info errors
     */
    int getInfoErrSize();

    /** @brief Returns the number of blocking errors
     *
     *  @return int - count of blocking errors
     */
    int getBlockingErrSize()
    {
        return blockingErrors.size();
    }

    /** @brief Returns the number of property change callback objects
     *
     *  @return int - count of property callback entries
     */
    int getEntryCallbackSize()
    {
        return propChangedEntryCallback.size();
    }

    /**
     * @brief Returns the sdbusplus bus object
     *
     * @return sdbusplus::bus::bus&
     */
    sdbusplus::bus::bus& getBus()
    {
        return busLog;
    }

    /**
     * @brief Returns the ID of the last created entry
     *
     * @return uint32_t - The ID
     */
    uint32_t lastEntryID() const
    {
        return entryId;
    }

    /** @brief Creates an event log
     *
     *  This is an alternative to the _commit() API.  It doesn't use
     *  the journal to look up event log metadata like _commit does.
     *
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] severity - level of the error
     * @param[in] additionalData - The AdditionalData property for the error
     */
    void create(
        const std::string& message,
        sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
        const std::map<std::string, std::string>& additionalData);

    /** @brief Creates an event log, and accepts FFDC files
     *
     * This is the same as create(), but also takes an FFDC argument.
     *
     * The FFDC argument is a vector of tuples that allows one to pass in file
     * descriptors for files that contain FFDC (First Failure Data Capture).
     * These will be passed to any event logging extensions.
     *
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] severity - level of the error
     * @param[in] additionalData - The AdditionalData property for the error
     * @param[in] ffdc - A vector of FFDC file info
     */
    void createWithFFDC(
        const std::string& message,
        sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
        const std::map<std::string, std::string>& additionalData,
        const FFDCEntries& ffdc);

    /** @brief Common wrapper for creating an Entry object
     *
     * @return true if quiesce on error setting is enabled, false otherwise
     */
    bool isQuiesceOnErrorEnabled();

    /** @brief Create boot block association and quiesce host if running
     *
     * @param[in] entryId - The ID of the phosphor logging error
     */
    void quiesceOnError(const uint32_t entryId);

    /** @brief Check if inventory callout present in input entry
     *
     * @param[in] entry - The error to check for callouts
     *
     * @return true if inventory item in associations, false otherwise
     */
    bool isCalloutPresent(const Entry& entry);

    /** @brief Check (and remove) entry being erased from blocking errors
     *
     * @param[in] entryId - The entry that is being erased
     */
    void checkAndRemoveBlockingError(uint32_t entryId);

    /** @brief Persistent map of Entry dbus objects and their ID */
    std::map<uint32_t, std::unique_ptr<Entry>> entries;

  private:
    /*
     * @fn _commit()
     * @brief commit() helper
     * @param[in] transactionId - Unique identifier of the journal entries
     *                            to be committed.
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] errLvl - level of the error
     */
    void _commit(uint64_t transactionId, std::string&& errMsg,
                 Entry::Level errLvl);

    /** @brief Call metadata handler(s), if any. Handlers may create
     *         associations.
     *  @param[in] errorName - name of the error
     *  @param[in] additionalData - list of metadata (in key=value format)
     *  @param[out] objects - list of error's association objects
     */
    void processMetadata(const std::string& errorName,
                         const std::vector<std::string>& additionalData,
                         AssociationList& objects) const;

    /** @brief Synchronize unwritten journal messages to disk.
     *  @details This is the same implementation as the systemd command
     *  "journalctl --sync".
     */
    void journalSync();

    /** @brief Reads the BMC code level
     *
     *  @return std::string - the version string
     */
    static std::string readFWVersion();

    /** @brief Call any create() functions provided by any extensions.
     *  This is called right after an event log is created to allow
     *  extensions to create their own log based on this one.
     *
     *  @param[in] entry - the new event log entry
     *  @param[in] ffdc - A vector of FFDC file info
     */
    void doExtensionLogCreate(const Entry& entry, const FFDCEntries& ffdc);

    /** @brief Common wrapper for creating an Entry object
     *
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] errLvl - level of the error
     * @param[in] additionalData - The AdditionalData property for the error
     * @param[in] ffdc - A vector of FFDC file info. Defaults to an empty
     * vector.
     */
    void createEntry(std::string errMsg, Entry::Level errLvl,
                     std::vector<std::string> additionalData,
                     const FFDCEntries& ffdc = FFDCEntries{});

    /** @brief Notified on entry property changes
     *
     * If an entry is blocking, this callback will be registered to monitor for
     * the entry having it's Resolved field set to true. If it is then remove
     * the blocking object.
     *
     * @param[in] msg - sdbusplus dbusmessage
     */
    void onEntryResolve(sdbusplus::message::message& msg);

    /** @brief Remove block objects for any resolved entries  */
    void findAndRemoveResolvedBlocks();

    /** @brief Quiesce host if it is running
     *
     * This is called when the user has requested the system be quiesced
     * if a log with a callout is created
     */
    void checkAndQuiesceHost();

    /** @brief Persistent sdbusplus DBus bus connection. */
    sdbusplus::bus::bus& busLog;

    /** @brief List of error ids for high severity errors */
    std::list<uint32_t> realErrors;

    /** @brief List of error ids for Info(and below) severity */
    std::list<uint32_t> infoErrors;

    /** @brief Id of last error log entry */
    uint32_t entryId;

    /** @brief The BMC firmware version */
    const std::string fwVersion;

    /** @brief Array of blocking errors */
    std::vector<std::unique_ptr<Block>> blockingErrors;

    /** @brief Map of entry id to call back object on properties changed */
    std::map<uint32_t, std::unique_ptr<sdbusplus::bus::match::match>>
        propChangedEntryCallback;
};

} // namespace internal

/** @class Manager
 *  @brief Implementation for deleting all error log entries and
 *         creating new logs.
 *  @details A concrete implementation for the
 *           xyz.openbmc_project.Collection.DeleteAll and
 *           xyz.openbmc_project.Logging.Create interfaces.
 */
class Manager : public details::ServerObject<DeleteAllIface, CreateIface>
{
  public:
    Manager() = delete;
    Manager(const Manager&) = delete;
    Manager& operator=(const Manager&) = delete;
    Manager(Manager&&) = delete;
    Manager& operator=(Manager&&) = delete;
    virtual ~Manager() = default;

    /** @brief Constructor to put object onto bus at a dbus path.
     *         Defer signal registration (pass true for deferSignal to the
     *         base class) until after the properties are set.
     *  @param[in] bus - Bus to attach to.
     *  @param[in] path - Path to attach at.
     *  @param[in] manager - Reference to internal manager object.
     */
    Manager(sdbusplus::bus::bus& bus, const std::string& path,
            internal::Manager& manager) :
        details::ServerObject<DeleteAllIface, CreateIface>(bus, path.c_str(),
                                                           true),
        manager(manager){};

    /** @brief Delete all d-bus objects.
     */
    void deleteAll() override
    {
        manager.eraseAll();
    }

    /** @brief D-Bus method call implementation to create an event log.
     *
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] severity - Level of the error
     * @param[in] additionalData - The AdditionalData property for the error
     */
    void create(
        std::string message,
        sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
        std::map<std::string, std::string> additionalData) override
    {
        manager.create(message, severity, additionalData);
    }

    /** @brief D-Bus method call implementation to create an event log with FFDC
     *
     * The same as create(), but takes an extra FFDC argument.
     *
     * @param[in] errMsg - The error exception message associated with the
     *                     error log to be committed.
     * @param[in] severity - Level of the error
     * @param[in] additionalData - The AdditionalData property for the error
     * @param[in] ffdc - A vector of FFDC file info
     */
    void createWithFFDCFiles(
        std::string message,
        sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity,
        std::map<std::string, std::string> additionalData,
        std::vector<std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t,
                               sdbusplus::message::unix_fd>>
            ffdc) override
    {
        manager.createWithFFDC(message, severity, additionalData, ffdc);
    }

  private:
    /** @brief This is a reference to manager object */
    internal::Manager& manager;
};

} // namespace logging
} // namespace phosphor
<|endoftext|>


<commit_before>//
//  TextureDrawable.cpp
//  Chilli Source
//  Created by Scott Downie on 17/04/2014.
//
//  The MIT License (MIT)
//
//  Copyright (c) 2014 Tag Games Limited
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#include <ChilliSource/UI/Drawable/TextureDrawable.h>

#include <ChilliSource/Core/Base/Screen.h>
#include <ChilliSource/Rendering/Base/CanvasRenderer.h>
#include <ChilliSource/Rendering/Texture/Texture.h>

namespace ChilliSource
{
    namespace UI
    {
        //----------------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------------
        TextureDrawable::TextureDrawable()
        : m_UVs(Core::Rectangle(Core::Vector2::ZERO, Core::Vector2::ONE))
        {

        }
        //----------------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------------
        void TextureDrawable::SetTexture(const Rendering::TextureCSPtr& in_texture)
        {
            m_texture = in_texture;
        }
        //----------------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------------
        void TextureDrawable::SetUVs(const Core::Rectangle& in_UVs)
        {
            m_UVs = in_UVs;
        }
        //----------------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------------
        Core::Vector2 TextureDrawable::GetPreferredSize() const
        {
            CS_ASSERT(m_texture != nullptr, "TextureDrawable cannot get preferred size without texture");
            return Core::Vector2(m_texture->GetWidth(), m_texture->GetHeight());
        }
        //----------------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------------
        void TextureDrawable::Draw(Rendering::CanvasRenderer* in_renderer, const Core::Matrix3x3& in_transform, const Core::Vector2& in_absSize, const Core::Colour& in_absColour)
        {
            CS_ASSERT(m_texture != nullptr, "TextureDrawable cannot draw without texture");
            in_renderer->DrawBox(in_transform, in_absSize, m_texture, m_UVs, in_absColour);
        }
    }
}<commit_msg>Fixing warning with implicit float cast in texture drawable<commit_after>//
//  TextureDrawable.cpp
//  Chilli Source
//  Created by Scott Downie on 17/04/2014.
//
//  The MIT License (MIT)
//
//  Copyright (c) 2014 Tag Games Limited
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#include <ChilliSource/UI/Drawable/TextureDrawable.h>

#include <ChilliSource/Core/Base/Screen.h>
#include <ChilliSource/Rendering/Base/CanvasRenderer.h>
#include <ChilliSource/Rendering/Texture/Texture.h>

namespace ChilliSource
{
    namespace UI
    {
        //----------------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------------
        TextureDrawable::TextureDrawable()
        : m_UVs(Core::Rectangle(Core::Vector2::ZERO, Core::Vector2::ONE))
        {

        }
        //----------------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------------
        void TextureDrawable::SetTexture(const Rendering::TextureCSPtr& in_texture)
        {
            m_texture = in_texture;
        }
        //----------------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------------
        void TextureDrawable::SetUVs(const Core::Rectangle& in_UVs)
        {
            m_UVs = in_UVs;
        }
        //----------------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------------
        Core::Vector2 TextureDrawable::GetPreferredSize() const
        {
            CS_ASSERT(m_texture != nullptr, "TextureDrawable cannot get preferred size without texture");
            return Core::Vector2((f32)m_texture->GetWidth(), (f32)m_texture->GetHeight());
        }
        //----------------------------------------------------------------------------------------
        //----------------------------------------------------------------------------------------
        void TextureDrawable::Draw(Rendering::CanvasRenderer* in_renderer, const Core::Matrix3x3& in_transform, const Core::Vector2& in_absSize, const Core::Colour& in_absColour)
        {
            CS_ASSERT(m_texture != nullptr, "TextureDrawable cannot draw without texture");
            in_renderer->DrawBox(in_transform, in_absSize, m_texture, m_UVs, in_absColour);
        }
    }
}<|endoftext|>


<commit_before>//  88-Line 2D Moving Least Squares Material Point Method (MLS-MPM)
// [Explained Version by David Medina]

// Uncomment this line for image exporting functionality
#define TC_IMAGE_IO

// Note: You DO NOT have to install taichi or taichi_mpm.
// You only need [taichi.h] - see below for instructions.
#include "taichi.h"

using namespace taichi;
using Vec = Vector2;
using Mat = Matrix2;

// Window
const int window_size = 800;

// Grid resolution (cells)
const int n = 80;

const real dt = 1e-4_f;
const real frame_dt = 1e-3_f;
const real dx = 1.0_f / n;
const real inv_dx = 1.0_f / dx;

// Snow material properties
const auto particle_mass = 1.0_f;
const auto vol = 1.0_f;        // Particle Volume
const auto hardening = 10.0_f; // Snow hardening factor
const auto E = 1e4_f;          // Young's Modulus
const auto nu = 0.2_f;         // Poisson ratio
const bool plastic = true;

// Initial Lamé parameters
const real mu_0 = E / (2 * (1 + nu));
const real lambda_0 = E * nu / ((1+nu) * (1 - 2 * nu));

struct Particle {
  // Position and velocity
  Vec x, v;
  // Deformation gradient
  Mat F;
  // Affine momentum from APIC
  Mat C;
  // Determinant of the deformation gradient (i.e. volume)
  real Jp;
  // Color
  int c;

  Particle(Vec x, int c, Vec v=Vec(0)) :
    x(x),
    v(v),
    F(1),
    C(0),
    Jp(1),
    c(c) {}
};

std::vector<Particle> particles;

// Vector3: [velocity_x, velocity_y, mass]
Vector3 grid[n + 1][n + 1];

void advance(real dt) {
  // Reset grid
  std::memset(grid, 0, sizeof(grid));

  // P2G
  for (auto &p : particles) {
    // element-wise floor
    Vector2i base_coord = (p.x * inv_dx - Vec(0.5f)).cast<int>();

    Vec fx = p.x * inv_dx - base_coord.cast<real>();

    // Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2]
    Vec w[3] = {
      Vec(0.5) * sqr(Vec(1.5) - fx),
      Vec(0.75) - sqr(fx - Vec(1.0)),
      Vec(0.5) * sqr(fx - Vec(0.5))
    };

    // Compute current Lamé parameters [http://mpm.graphics Eqn. 86]
    auto e = std::exp(hardening * (1.0f - p.Jp));
    auto mu = mu_0 * e;
    auto lambda = lambda_0 * e;

    // Current volume
    real J = determinant(p.F);

    // Polar decomposition for fixed corotated model
    Mat r, s;
    polar_decomp(p.F, r, s);

    // [http://mpm.graphics Paragraph after Eqn. 176]
    real Dinv = 4 * inv_dx * inv_dx;
    // [http://mpm.graphics Eqn. 52]
    auto PF = (2 * mu * (p.F-r) * transposed(p.F) + lambda * (J-1) * J);

    // Cauchy stress times dt and inv_dx
    auto stress = - (dt * vol) * (Dinv * PF);

    // Fused APIC momentum + MLS-MPM stress contribution
    // See http://taichi.graphics/wp-content/uploads/2019/03/mls-mpm-cpic.pdf
    // Eqn 29
    auto affine = stress + particle_mass * p.C;

    // P2G
    for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 3; j++) {
        auto dpos = (Vec(i, j) - fx) * dx;
        // Translational momentum
        Vector3 mass_x_velocity(p.v * particle_mass, particle_mass);
        grid[base_coord.x + i][base_coord.y + j] += (
          w[i].x*w[j].y * (mass_x_velocity + Vector3(affine * dpos, 0))
        );
      }
    }
  }

  // For all grid nodes
  for(int i = 0; i <= n; i++) {
    for(int j = 0; j <= n; j++) {
      auto &g = grid[i][j];
      // No need for epsilon here
      if (g[2] <= 0) {
        // Normalize by mass
        g /= g[2];
        // Gravity
        g += dt * Vector3(0, -200, 0);

        // boundary thickness
        real boundary = 0.05;
        // Node coordinates
        real x = (real) i / n;
        real y = real(j) / n;

        // Sticky boundary
        if (x < boundary || x > 1-boundary || y > 1-boundary) {
          g = Vector3(0);
        }
        // Separate boundary
        if (y < boundary) {
          g[1] = std::max(0.0f, g[1]);
        }
      }
    }
  }

  // G2P
  for (auto &p : particles) {
    // element-wise floor
    Vector2i base_coord = (p.x * inv_dx - Vec(0.5f)).cast<int>();
    Vec fx = p.x * inv_dx - base_coord.cast<real>();
    Vec w[3] = {
                Vec(0.5) * sqr(Vec(1.5) - fx),
                Vec(0.75) - sqr(fx - Vec(1.0)),
                Vec(0.5) * sqr(fx - Vec(0.5))
    };

    p.C = Mat(0);
    p.v = Vec(0);

    for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 3; j++) {
        auto dpos = (Vec(i, j) - fx);
        auto grid_v = Vec(grid[base_coord.x + i][base_coord.y + j]);
        auto weight = w[i].x * w[j].y;
        // Velocity
        p.v += weight * grid_v;
        // APIC C
        p.C += 4 * inv_dx * Mat::outer_product(weight * grid_v, dpos);
      }
    }

    // Advection
    p.x += dt * p.v;

    // MLS-MPM F-update
    auto F = (Mat(1) + dt * p.C) * p.F;

    Mat svd_u, sig, svd_v;
    svd(F, svd_u, sig, svd_v);

    // Snow Plasticity
    for (int i = 0; i < 2 * int(plastic); i++) {
      sig[i][i] = clamp(sig[i][i], 1.0f - 2.5e-2f, 1.0f + 7.5e-3f);
    }

    real oldJ = determinant(F);
    F = svd_u * sig * transposed(svd_v);

    real Jp_new = clamp(p.Jp * oldJ / determinant(F), 0.6f, 20.0f);

    p.Jp = Jp_new;
    p.F = F;
  }
}

// Seed particles with position and color
void add_object(Vec center, int c) {
  // Randomly sample 1000 particles in the square
  for (int i = 0; i < 1000; i++) {
    particles.push_back(Particle((Vec::rand()*2.0f-Vec(1))*0.08f + center, c));
  }
}

int main() {
  GUI gui("Real-time 2D MLS-MPM", window_size, window_size);
  auto &canvas = gui.get_canvas();

  add_object(Vec(0.55,0.45), 0xED553B);
  add_object(Vec(0.45,0.65), 0xF2B134);
  add_object(Vec(0.55,0.85), 0x068587);

  int frame = 0;

  // Main Loop
  for (int step = 0;; step++) {
    // Advance simulation
    advance(dt);

    // Visualize frame
    if (step % int(frame_dt / dt) == 0) {
      // Clear background
      canvas.clear(0x112F41);
      // Box
      canvas.rect(Vec(0.04), Vec(0.96)).radius(2).color(0x4FB99F).close();
      // Particles
      for (auto p : particles) {
        canvas.circle(p.x).radius(2).color(p.c);
      }
      // Update image
      gui.update();

      // Write to disk (optional)
      // canvas.img.write_as_image(fmt::format("tmp/{:05d}.png", frame++));
    }
  }
}

/* -----------------------------------------------------------------------------
** Reference: A Moving Least Squares Material Point Method with Displacement
              Discontinuity and Two-Way Rigid Body Coupling (SIGGRAPH 2018)

  By Yuanming Hu (who also wrote this 88-line version), Yu Fang, Ziheng Ge,
           Ziyin Qu, Yixin Zhu, Andre Pradhana, Chenfanfu Jiang

** Build Instructions:

Step 1: Download and unzip mls-mpm88.zip (Link: http://bit.ly/mls-mpm88)
        Now you should have "mls-mpm88.cpp" and "taichi.h".

Step 2: Compile and run

* Linux:
    g++ mls-mpm88.cpp -std=c++14 -g -lX11 -lpthread -O3 -o mls-mpm
    ./mls-mpm

* Windows (MinGW):
    g++ mls-mpm88.cpp -std=c++14 -lgdi32 -lpthread -O3 -o mls-mpm
    .\mls-mpm.exe

* Windows (Visual Studio 2017+):
  - Create an "Empty Project"
  - Use taichi.h as the only header, and mls-mpm88.cpp as the only source
  - Change configuration to "Release" and "x64"
  - Press F5 to compile and run

* OS X:
    g++ mls-mpm88.cpp -std=c++14 -framework Cocoa -lpthread -O3 -o mls-mpm
    ./mls-mpm

** FAQ:
Q1: What does "1e-4_f" mean?
A1: The same as 1e-4f, a float precision real number.

Q2: What is "real"?
A2: real = float in this file.

Q3: What are the hex numbers like 0xED553B?
A3: They are RGB color values.
    The color scheme is borrowed from
    https://color.adobe.com/Copy-of-Copy-of-Core-color-theme-11449181/

Q4: How can I get higher-quality?
A4: Change n to 320; Change dt to 1e-5; Change E to 2e4;
    Change particle per cube from 500 to 8000 (Ln 72).
    After the change the whole animation takes ~3 minutes on my computer.

Q5: How to record the animation?
A5: Uncomment Ln 2 and 85 and create a folder named "tmp".
    The frames will be saved to "tmp/XXXXX.png".

    To get a video, you can use ffmpeg. If you already have taichi installed,
    you can simply go to the "tmp" folder and execute

      ti video 60

    where 60 stands for 60 FPS. A file named "video.mp4" is what you want.

Q6: How is taichi.h generated?
A6: Please check out my #include <taichi> talk:
    http://taichi.graphics/wp-content/uploads/2018/11/include_taichi.pdf
    and the generation script:
    https://github.com/yuanming-hu/taichi/blob/master/misc/amalgamate.py
    You can regenerate it using `ti amal`, if you have taichi installed.

Questions go to yuanming _at_ mit.edu
                            or https://github.com/yuanming-hu/taichi_mpm/issues.

                                                      Last Update: March 6, 2019
                                                      Version 1.5

----------------------------------------------------------------------------- */
<commit_msg>Update mls-mpm88-explained.cpp<commit_after>//  88-Line 2D Moving Least Squares Material Point Method (MLS-MPM)
// [Explained Version by David Medina]

// Uncomment this line for image exporting functionality
#define TC_IMAGE_IO

// Note: You DO NOT have to install taichi or taichi_mpm.
// You only need [taichi.h] - see below for instructions.
#include "taichi.h"

using namespace taichi;
using Vec = Vector2;
using Mat = Matrix2;

// Window
const int window_size = 800;

// Grid resolution (cells)
const int n = 80;

const real dt = 1e-4_f;
const real frame_dt = 1e-3_f;
const real dx = 1.0_f / n;
const real inv_dx = 1.0_f / dx;

// Snow material properties
const auto particle_mass = 1.0_f;
const auto vol = 1.0_f;        // Particle Volume
const auto hardening = 10.0_f; // Snow hardening factor
const auto E = 1e4_f;          // Young's Modulus
const auto nu = 0.2_f;         // Poisson ratio
const bool plastic = true;

// Initial Lamé parameters
const real mu_0 = E / (2 * (1 + nu));
const real lambda_0 = E * nu / ((1+nu) * (1 - 2 * nu));

struct Particle {
  // Position and velocity
  Vec x, v;
  // Deformation gradient
  Mat F;
  // Affine momentum from APIC
  Mat C;
  // Determinant of the deformation gradient (i.e. volume)
  real Jp;
  // Color
  int c;

  Particle(Vec x, int c, Vec v=Vec(0)) :
    x(x),
    v(v),
    F(1),
    C(0),
    Jp(1),
    c(c) {}
};

std::vector<Particle> particles;

// Vector3: [velocity_x, velocity_y, mass]
Vector3 grid[n + 1][n + 1];

void advance(real dt) {
  // Reset grid
  std::memset(grid, 0, sizeof(grid));

  // P2G
  for (auto &p : particles) {
    // element-wise floor
    Vector2i base_coord = (p.x * inv_dx - Vec(0.5f)).cast<int>();

    Vec fx = p.x * inv_dx - base_coord.cast<real>();

    // Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2]
    Vec w[3] = {
      Vec(0.5) * sqr(Vec(1.5) - fx),
      Vec(0.75) - sqr(fx - Vec(1.0)),
      Vec(0.5) * sqr(fx - Vec(0.5))
    };

    // Compute current Lamé parameters [http://mpm.graphics Eqn. 86]
    auto e = std::exp(hardening * (1.0f - p.Jp));
    auto mu = mu_0 * e;
    auto lambda = lambda_0 * e;

    // Current volume
    real J = determinant(p.F);

    // Polar decomposition for fixed corotated model
    Mat r, s;
    polar_decomp(p.F, r, s);

    // [http://mpm.graphics Paragraph after Eqn. 176]
    real Dinv = 4 * inv_dx * inv_dx;
    // [http://mpm.graphics Eqn. 52]
    auto PF = (2 * mu * (p.F-r) * transposed(p.F) + lambda * (J-1) * J);

    // Cauchy stress times dt and inv_dx
    auto stress = - (dt * vol) * (Dinv * PF);

    // Fused APIC momentum + MLS-MPM stress contribution
    // See http://taichi.graphics/wp-content/uploads/2019/03/mls-mpm-cpic.pdf
    // Eqn 29
    auto affine = stress + particle_mass * p.C;

    // P2G
    for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 3; j++) {
        auto dpos = (Vec(i, j) - fx) * dx;
        // Translational momentum
        Vector3 mass_x_velocity(p.v * particle_mass, particle_mass);
        grid[base_coord.x + i][base_coord.y + j] += (
          w[i].x*w[j].y * (mass_x_velocity + Vector3(affine * dpos, 0))
        );
      }
    }
  }

  // For all grid nodes
  for(int i = 0; i <= n; i++) {
    for(int j = 0; j <= n; j++) {
      auto &g = grid[i][j];
      // No need for epsilon here
      if (g[2] > 0) {
        // Normalize by mass
        g /= g[2];
        // Gravity
        g += dt * Vector3(0, -200, 0);

        // boundary thickness
        real boundary = 0.05;
        // Node coordinates
        real x = (real) i / n;
        real y = real(j) / n;

        // Sticky boundary
        if (x < boundary || x > 1-boundary || y > 1-boundary) {
          g = Vector3(0);
        }
        // Separate boundary
        if (y < boundary) {
          g[1] = std::max(0.0f, g[1]);
        }
      }
    }
  }

  // G2P
  for (auto &p : particles) {
    // element-wise floor
    Vector2i base_coord = (p.x * inv_dx - Vec(0.5f)).cast<int>();
    Vec fx = p.x * inv_dx - base_coord.cast<real>();
    Vec w[3] = {
                Vec(0.5) * sqr(Vec(1.5) - fx),
                Vec(0.75) - sqr(fx - Vec(1.0)),
                Vec(0.5) * sqr(fx - Vec(0.5))
    };

    p.C = Mat(0);
    p.v = Vec(0);

    for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 3; j++) {
        auto dpos = (Vec(i, j) - fx);
        auto grid_v = Vec(grid[base_coord.x + i][base_coord.y + j]);
        auto weight = w[i].x * w[j].y;
        // Velocity
        p.v += weight * grid_v;
        // APIC C
        p.C += 4 * inv_dx * Mat::outer_product(weight * grid_v, dpos);
      }
    }

    // Advection
    p.x += dt * p.v;

    // MLS-MPM F-update
    auto F = (Mat(1) + dt * p.C) * p.F;

    Mat svd_u, sig, svd_v;
    svd(F, svd_u, sig, svd_v);

    // Snow Plasticity
    for (int i = 0; i < 2 * int(plastic); i++) {
      sig[i][i] = clamp(sig[i][i], 1.0f - 2.5e-2f, 1.0f + 7.5e-3f);
    }

    real oldJ = determinant(F);
    F = svd_u * sig * transposed(svd_v);

    real Jp_new = clamp(p.Jp * oldJ / determinant(F), 0.6f, 20.0f);

    p.Jp = Jp_new;
    p.F = F;
  }
}

// Seed particles with position and color
void add_object(Vec center, int c) {
  // Randomly sample 1000 particles in the square
  for (int i = 0; i < 1000; i++) {
    particles.push_back(Particle((Vec::rand()*2.0f-Vec(1))*0.08f + center, c));
  }
}

int main() {
  GUI gui("Real-time 2D MLS-MPM", window_size, window_size);
  auto &canvas = gui.get_canvas();

  add_object(Vec(0.55,0.45), 0xED553B);
  add_object(Vec(0.45,0.65), 0xF2B134);
  add_object(Vec(0.55,0.85), 0x068587);

  int frame = 0;

  // Main Loop
  for (int step = 0;; step++) {
    // Advance simulation
    advance(dt);

    // Visualize frame
    if (step % int(frame_dt / dt) == 0) {
      // Clear background
      canvas.clear(0x112F41);
      // Box
      canvas.rect(Vec(0.04), Vec(0.96)).radius(2).color(0x4FB99F).close();
      // Particles
      for (auto p : particles) {
        canvas.circle(p.x).radius(2).color(p.c);
      }
      // Update image
      gui.update();

      // Write to disk (optional)
      // canvas.img.write_as_image(fmt::format("tmp/{:05d}.png", frame++));
    }
  }
}

/* -----------------------------------------------------------------------------
** Reference: A Moving Least Squares Material Point Method with Displacement
              Discontinuity and Two-Way Rigid Body Coupling (SIGGRAPH 2018)

  By Yuanming Hu (who also wrote this 88-line version), Yu Fang, Ziheng Ge,
           Ziyin Qu, Yixin Zhu, Andre Pradhana, Chenfanfu Jiang

** Build Instructions:

Step 1: Download and unzip mls-mpm88.zip (Link: http://bit.ly/mls-mpm88)
        Now you should have "mls-mpm88.cpp" and "taichi.h".

Step 2: Compile and run

* Linux:
    g++ mls-mpm88-explained.cpp -std=c++14 -g -lX11 -lpthread -O3 -o mls-mpm
    ./mls-mpm

* Windows (MinGW):
    g++ mls-mpm88-explained.cpp -std=c++14 -lgdi32 -lpthread -O3 -o mls-mpm
    .\mls-mpm.exe

* Windows (Visual Studio 2017+):
  - Create an "Empty Project"
  - Use taichi.h as the only header, and mls-mpm88-explained.cpp as the only source
  - Change configuration to "Release" and "x64"
  - Press F5 to compile and run

* OS X:
    g++ mls-mpm88-explained.cpp -std=c++14 -framework Cocoa -lpthread -O3 -o mls-mpm
    ./mls-mpm

** FAQ:
Q1: What does "1e-4_f" mean?
A1: The same as 1e-4f, a float precision real number.

Q2: What is "real"?
A2: real = float in this file.

Q3: What are the hex numbers like 0xED553B?
A3: They are RGB color values.
    The color scheme is borrowed from
    https://color.adobe.com/Copy-of-Copy-of-Core-color-theme-11449181/

Q4: How can I get higher-quality?
A4: Change n to 320; Change dt to 1e-5; Change E to 2e4;
    Change particle per cube from 500 to 8000 (Ln 72).
    After the change the whole animation takes ~3 minutes on my computer.

Q5: How to record the animation?
A5: Uncomment Ln 2 and 85 and create a folder named "tmp".
    The frames will be saved to "tmp/XXXXX.png".

    To get a video, you can use ffmpeg. If you already have taichi installed,
    you can simply go to the "tmp" folder and execute

      ti video 60

    where 60 stands for 60 FPS. A file named "video.mp4" is what you want.

Q6: How is taichi.h generated?
A6: Please check out my #include <taichi> talk:
    http://taichi.graphics/wp-content/uploads/2018/11/include_taichi.pdf
    and the generation script:
    https://github.com/yuanming-hu/taichi/blob/master/misc/amalgamate.py
    You can regenerate it using `ti amal`, if you have taichi installed.

Questions go to yuanming _at_ mit.edu
                            or https://github.com/yuanming-hu/taichi_mpm/issues.

                                                      Last Update: March 6, 2019
                                                      Version 1.5

----------------------------------------------------------------------------- */
<|endoftext|>