<commit_before>//
// Copyright (c) 2014, 2015, 2016, 2017 CNRS
// Authors: Florent Lamiraux, Joseph Mirabel
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#include <hpp/core/continuous-collision-checking.hh>

#include <limits>
#include <pinocchio/multibody/geometry.hpp>
#include <hpp/util/debug.hh>
#include <hpp/core/collision-path-validation-report.hh>
#include <hpp/core/straight-path.hh>
#include <hpp/core/path-vector.hh>

#include "continuous-collision-checking/body-pair-collision.hh"

namespace hpp {
  namespace core {
    namespace {
      using continuousCollisionChecking::BodyPairCollision;
      using continuousCollisionChecking::BodyPairCollisions_t;
      using continuousCollisionChecking::BodyPairCollisionPtr_t;

      typedef std::pair<se3::JointIndex, se3::JointIndex> JointIndexPair_t;

      struct JointIndexPairCompare_t {
	bool operator() (const JointIndexPair_t& p0, const JointIndexPair_t& p1) const
	{
	  if (p0.first < p1.first) return true;
	  if (p0.first > p1.first) return false;
	  return (p0.second < p1.second);
	}
      };

      // typedef std::set<JointIndexPair_t, JointIndexPairCompare_t> JointIndexPairSet_t;
      typedef std::map<JointIndexPair_t, BodyPairCollisionPtr_t, JointIndexPairCompare_t> BodyPairCollisionMap_t;
    }

    /// Validate interval centered on a path parameter
    /// \param config Configuration at abscissa tmin on the path.
    /// \param tmin parameter value in the path interval of definition
    /// \retval tmin lower bound of valid interval if reverve is true,
    ///              upper bound of valid interval if reverse is false.
    ///              other bound of valid interval is input tmin.
    /// \return true if the configuration is collision free for this parameter
    ///         value, false otherwise.
    bool ContinuousCollisionChecking::validateConfiguration
    (const Configuration_t& config, const value_type& t,
     interval_t& interval, PathValidationReportPtr_t& report)
    {
      interval.first = -std::numeric_limits <value_type>::infinity ();
      interval.second = std::numeric_limits <value_type>::infinity ();
      interval_t tmpInt;
      robot_->currentConfiguration (config);
      robot_->computeForwardKinematics();
      robot_->updateGeometryPlacements();
      for (BodyPairCollisions_t::iterator itPair = bodyPairCollisions_.begin ();
	   itPair != bodyPairCollisions_.end (); ++itPair) {
	CollisionValidationReportPtr_t collisionReport;
        // the valid interval will not be greater than "interval" so we do not
        // need to perform collision checking on a greater interval.
        tmpInt = interval;
	if (!(*itPair)->validateConfiguration (t, tmpInt, collisionReport)) {
	  report = CollisionPathValidationReportPtr_t
	    (new CollisionPathValidationReport);
	  report->configurationReport = collisionReport;
	  report->parameter = t;
	  return false;
	} else {
	  interval.first = std::max (interval.first, tmpInt.first);
	  interval.second = std::min (interval.second, tmpInt.second);
	  assert ((*itPair)->path()->length() == 0 || interval.second > interval.first);
	  assert (interval.first <= t);
	  assert (t <= interval.second);
	}
      }
      return true;
    }

    bool ContinuousCollisionChecking::validate
    (const PathPtr_t& path, bool reverse, PathPtr_t& validPart,
     PathValidationReportPtr_t& report)
    {
      if (PathVectorPtr_t pv = HPP_DYNAMIC_PTR_CAST (PathVector, path)) {
	PathVectorPtr_t validPathVector = PathVector::create
	  (path->outputSize (), path->outputDerivativeSize ());
	validPart = validPathVector;
	PathPtr_t localValidPart;
	if (reverse) {
	  value_type param = path->length ();
	  std::deque <PathPtr_t> paths;
	  for (std::size_t i=pv->numberPaths () + 1; i != 0 ; --i) {
	    PathPtr_t localPath (pv->pathAtRank (i-1));
	    if (validate (localPath, reverse, localValidPart, report)) {
	      paths.push_front (localPath->copy ());
	      param -= localPath->length ();
	    } else {
	      report->parameter += param - localPath->length ();
	      paths.push_front (localValidPart->copy ());
	      for (std::deque <PathPtr_t>::const_iterator it = paths.begin ();
		   it != paths.end (); ++it) {
		validPathVector->appendPath (*it);
	      }
	      return false;
	    }
	  }
	  return true;
	} else {
	  value_type param = 0;
	  for (std::size_t i=0; i < pv->numberPaths (); ++i) {
	    PathPtr_t localPath (pv->pathAtRank (i));
	    if (validate (localPath, reverse, localValidPart, report)) {
	      validPathVector->appendPath (localPath->copy ());
	      param += localPath->length ();
	    } else {
	      report->parameter += param;
	      validPathVector->appendPath (localValidPart->copy ());
	      return false;
	    }
	  }
	  return true;
	}
      }
      return validateStraightPath (path, reverse, validPart, report);
    }

    void ContinuousCollisionChecking::addObstacle
    (const CollisionObjectConstPtr_t& object)
    {
      pinocchio::JointVector_t& jv = robot_->getJointVector ();
      for (size_type idx = 0; idx < jv.size (); ++idx) {
	BodyPtr_t body = (jv.at(idx))->linkedBody ();
	if (body) {
	  ConstObjectStdVector_t objects;
	  objects.push_back (object);
	  bodyPairCollisions_.push_back
	    (BodyPairCollision::create (jv.at(idx), objects, tolerance_));
	}
      }
    }

    void ContinuousCollisionChecking::removeObstacleFromJoint
    (const JointPtr_t& joint, const CollisionObjectConstPtr_t& obstacle)
    {
      bool removed = false;
      for (BodyPairCollisions_t::iterator itPair =
	     bodyPairCollisions_.begin ();
	   itPair != bodyPairCollisions_.end (); ++itPair) {
	if (!(*itPair)->joint_b () && (*itPair)->joint_a () == joint) {
	  if ((*itPair)->removeObjectTo_b (obstacle)) {
	    removed = true;
	    if ((*itPair)->pairs ().empty ()) {
	      bodyPairCollisions_.erase (itPair);
	    }
	  }
	}
      }
      if (!removed) {
	std::ostringstream oss;
	oss << "ContinuousCollisionChecking::removeObstacleFromJoint: obstacle \""
	    << obstacle->name () <<
	  "\" is not registered as obstacle for joint \"" << joint->name ()
	    << "\".";
	throw std::runtime_error (oss.str ());
      }
    }

    void ContinuousCollisionChecking::filterCollisionPairs
    (const RelativeMotion::matrix_type& relMotion)
    {
      // Loop over collision pairs and remove disabled ones.
      size_type ia, ib;
      for (BodyPairCollisions_t::iterator _colPair = bodyPairCollisions_.begin ();
          _colPair != bodyPairCollisions_.end ();) {
        const JointConstPtr_t& ja = (*_colPair)->joint_a(),
              jb = (*_colPair)->joint_b();
        ia = RelativeMotion::idx(ja);
        ib = RelativeMotion::idx(jb);
        switch (relMotion(ia, ib)) {
          case RelativeMotion::Parameterized:
            hppDout(info, "Parameterized collision pairs treated as Constrained");
          case RelativeMotion::Constrained:
            hppDout(info, "Disabling collision between joint "
                << (ja ? ja->name() : "universe") << " and "
                << (jb ? jb->name() : "universe"));
            disabledBodyPairCollisions_.push_back (*_colPair);
            _colPair = bodyPairCollisions_.erase (_colPair);
            break;
          case RelativeMotion::Unconstrained:
            ++_colPair;
            break;
          default:
            hppDout (warning, "RelativeMotionType not understood");
            ++_colPair;
            break;
        }
      }
    }

    ContinuousCollisionChecking::~ContinuousCollisionChecking ()
    {
    }

    ContinuousCollisionChecking::ContinuousCollisionChecking
    (const DevicePtr_t& robot, const value_type& tolerance) :
      robot_ (robot), tolerance_ (tolerance),
      bodyPairCollisions_ ()
    {
      // Build body pairs for collision checking
      // First auto-collision
      const se3::GeometryModel& gmodel = robot->geomModel ();
      JointPtr_t joint1, joint2;
      BodyPairCollisionMap_t bodyPairMap;
      for (std::size_t i = 0; i < gmodel.collisionPairs.size(); ++i)
      {
        const se3::CollisionPair& cp = gmodel.collisionPairs[i];
        JointIndexPair_t jp (gmodel.geometryObjects[cp.first ].parentJoint,
                             gmodel.geometryObjects[cp.second].parentJoint);

        BodyPairCollisionMap_t::iterator _bp = bodyPairMap.find(jp);

        if (_bp == bodyPairMap.end()) {
          joint1 = JointPtr_t(new Joint(robot_, jp.first));
          joint2 = JointPtr_t(new Joint(robot_, jp.second));
          bodyPairCollisions_.push_back (
              BodyPairCollision::create (joint2, joint1, tolerance_));
          bodyPairMap[jp] = bodyPairCollisions_.back();
        }
        bodyPairMap[jp]->addCollisionPair (
            CollisionObjectConstPtr_t (new pinocchio::CollisionObject(robot, cp.first )),
            CollisionObjectConstPtr_t (new pinocchio::CollisionObject(robot, cp.second)));
      }
    }
  } // namespace core
} // namespace hpp
<commit_msg>[ContinuousCollisionChecking] Put configuration with smallest interval first.<commit_after>//
// Copyright (c) 2014, 2015, 2016, 2017 CNRS
// Authors: Florent Lamiraux, Joseph Mirabel
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#include <hpp/core/continuous-collision-checking.hh>

#include <limits>
#include <pinocchio/multibody/geometry.hpp>
#include <hpp/util/debug.hh>
#include <hpp/core/collision-path-validation-report.hh>
#include <hpp/core/straight-path.hh>
#include <hpp/core/path-vector.hh>

#include "continuous-collision-checking/body-pair-collision.hh"

namespace hpp {
  namespace core {
    namespace {
      using continuousCollisionChecking::BodyPairCollision;
      using continuousCollisionChecking::BodyPairCollisions_t;
      using continuousCollisionChecking::BodyPairCollisionPtr_t;

      typedef std::pair<se3::JointIndex, se3::JointIndex> JointIndexPair_t;

      struct JointIndexPairCompare_t {
	bool operator() (const JointIndexPair_t& p0, const JointIndexPair_t& p1) const
	{
	  if (p0.first < p1.first) return true;
	  if (p0.first > p1.first) return false;
	  return (p0.second < p1.second);
	}
      };

      // typedef std::set<JointIndexPair_t, JointIndexPairCompare_t> JointIndexPairSet_t;
      typedef std::map<JointIndexPair_t, BodyPairCollisionPtr_t, JointIndexPairCompare_t> BodyPairCollisionMap_t;
    }

    /// Validate interval centered on a path parameter
    /// \param config Configuration at abscissa tmin on the path.
    /// \param tmin parameter value in the path interval of definition
    /// \retval tmin lower bound of valid interval if reverve is true,
    ///              upper bound of valid interval if reverse is false.
    ///              other bound of valid interval is input tmin.
    /// \return true if the configuration is collision free for this parameter
    ///         value, false otherwise.
    bool ContinuousCollisionChecking::validateConfiguration
    (const Configuration_t& config, const value_type& t,
     interval_t& interval, PathValidationReportPtr_t& report)
    {
      interval.first = -std::numeric_limits <value_type>::infinity ();
      interval.second = std::numeric_limits <value_type>::infinity ();
      interval_t tmpInt;
      robot_->currentConfiguration (config);
      robot_->computeForwardKinematics();
      robot_->updateGeometryPlacements();
      BodyPairCollisions_t::iterator itMin;
      for (BodyPairCollisions_t::iterator itPair = bodyPairCollisions_.begin ();
	   itPair != bodyPairCollisions_.end (); ++itPair) {
	CollisionValidationReportPtr_t collisionReport;
        // the valid interval will not be greater than "interval" so we do not
        // need to perform collision checking on a greater interval.
        tmpInt = interval;
	if (!(*itPair)->validateConfiguration (t, tmpInt, collisionReport)) {
	  report = CollisionPathValidationReportPtr_t
	    (new CollisionPathValidationReport);
	  report->configurationReport = collisionReport;
	  report->parameter = t;
	  return false;
	} else {
          if (interval.second > tmpInt.second) itMin = itPair;
	  interval.first = std::max (interval.first, tmpInt.first);
	  interval.second = std::min (interval.second, tmpInt.second);
	  assert ((*itPair)->path()->length() == 0 || interval.second > interval.first);
	  assert (interval.first <= t);
	  assert (t <= interval.second);
	}
      }
      if (bodyPairCollisions_.size() > 1 && itMin != bodyPairCollisions_.begin())
        std::iter_swap (bodyPairCollisions_.begin(), itMin);
      return true;
    }

    bool ContinuousCollisionChecking::validate
    (const PathPtr_t& path, bool reverse, PathPtr_t& validPart,
     PathValidationReportPtr_t& report)
    {
      if (PathVectorPtr_t pv = HPP_DYNAMIC_PTR_CAST (PathVector, path)) {
	PathVectorPtr_t validPathVector = PathVector::create
	  (path->outputSize (), path->outputDerivativeSize ());
	validPart = validPathVector;
	PathPtr_t localValidPart;
	if (reverse) {
	  value_type param = path->length ();
	  std::deque <PathPtr_t> paths;
	  for (std::size_t i=pv->numberPaths () + 1; i != 0 ; --i) {
	    PathPtr_t localPath (pv->pathAtRank (i-1));
	    if (validate (localPath, reverse, localValidPart, report)) {
	      paths.push_front (localPath->copy ());
	      param -= localPath->length ();
	    } else {
	      report->parameter += param - localPath->length ();
	      paths.push_front (localValidPart->copy ());
	      for (std::deque <PathPtr_t>::const_iterator it = paths.begin ();
		   it != paths.end (); ++it) {
		validPathVector->appendPath (*it);
	      }
	      return false;
	    }
	  }
	  return true;
	} else {
	  value_type param = 0;
	  for (std::size_t i=0; i < pv->numberPaths (); ++i) {
	    PathPtr_t localPath (pv->pathAtRank (i));
	    if (validate (localPath, reverse, localValidPart, report)) {
	      validPathVector->appendPath (localPath->copy ());
	      param += localPath->length ();
	    } else {
	      report->parameter += param;
	      validPathVector->appendPath (localValidPart->copy ());
	      return false;
	    }
	  }
	  return true;
	}
      }
      return validateStraightPath (path, reverse, validPart, report);
    }

    void ContinuousCollisionChecking::addObstacle
    (const CollisionObjectConstPtr_t& object)
    {
      pinocchio::JointVector_t& jv = robot_->getJointVector ();
      for (size_type idx = 0; idx < jv.size (); ++idx) {
	BodyPtr_t body = (jv.at(idx))->linkedBody ();
	if (body) {
	  ConstObjectStdVector_t objects;
	  objects.push_back (object);
	  bodyPairCollisions_.push_back
	    (BodyPairCollision::create (jv.at(idx), objects, tolerance_));
	}
      }
    }

    void ContinuousCollisionChecking::removeObstacleFromJoint
    (const JointPtr_t& joint, const CollisionObjectConstPtr_t& obstacle)
    {
      bool removed = false;
      for (BodyPairCollisions_t::iterator itPair =
	     bodyPairCollisions_.begin ();
	   itPair != bodyPairCollisions_.end (); ++itPair) {
	if (!(*itPair)->joint_b () && (*itPair)->joint_a () == joint) {
	  if ((*itPair)->removeObjectTo_b (obstacle)) {
	    removed = true;
	    if ((*itPair)->pairs ().empty ()) {
	      bodyPairCollisions_.erase (itPair);
	    }
	  }
	}
      }
      if (!removed) {
	std::ostringstream oss;
	oss << "ContinuousCollisionChecking::removeObstacleFromJoint: obstacle \""
	    << obstacle->name () <<
	  "\" is not registered as obstacle for joint \"" << joint->name ()
	    << "\".";
	throw std::runtime_error (oss.str ());
      }
    }

    void ContinuousCollisionChecking::filterCollisionPairs
    (const RelativeMotion::matrix_type& relMotion)
    {
      // Loop over collision pairs and remove disabled ones.
      size_type ia, ib;
      for (BodyPairCollisions_t::iterator _colPair = bodyPairCollisions_.begin ();
          _colPair != bodyPairCollisions_.end ();) {
        const JointConstPtr_t& ja = (*_colPair)->joint_a(),
              jb = (*_colPair)->joint_b();
        ia = RelativeMotion::idx(ja);
        ib = RelativeMotion::idx(jb);
        switch (relMotion(ia, ib)) {
          case RelativeMotion::Parameterized:
            hppDout(info, "Parameterized collision pairs treated as Constrained");
          case RelativeMotion::Constrained:
            hppDout(info, "Disabling collision between joint "
                << (ja ? ja->name() : "universe") << " and "
                << (jb ? jb->name() : "universe"));
            disabledBodyPairCollisions_.push_back (*_colPair);
            _colPair = bodyPairCollisions_.erase (_colPair);
            break;
          case RelativeMotion::Unconstrained:
            ++_colPair;
            break;
          default:
            hppDout (warning, "RelativeMotionType not understood");
            ++_colPair;
            break;
        }
      }
    }

    ContinuousCollisionChecking::~ContinuousCollisionChecking ()
    {
    }

    ContinuousCollisionChecking::ContinuousCollisionChecking
    (const DevicePtr_t& robot, const value_type& tolerance) :
      robot_ (robot), tolerance_ (tolerance),
      bodyPairCollisions_ ()
    {
      // Build body pairs for collision checking
      // First auto-collision
      const se3::GeometryModel& gmodel = robot->geomModel ();
      JointPtr_t joint1, joint2;
      BodyPairCollisionMap_t bodyPairMap;
      for (std::size_t i = 0; i < gmodel.collisionPairs.size(); ++i)
      {
        const se3::CollisionPair& cp = gmodel.collisionPairs[i];
        JointIndexPair_t jp (gmodel.geometryObjects[cp.first ].parentJoint,
                             gmodel.geometryObjects[cp.second].parentJoint);

        BodyPairCollisionMap_t::iterator _bp = bodyPairMap.find(jp);

        if (_bp == bodyPairMap.end()) {
          joint1 = JointPtr_t(new Joint(robot_, jp.first));
          joint2 = JointPtr_t(new Joint(robot_, jp.second));
          bodyPairCollisions_.push_back (
              BodyPairCollision::create (joint2, joint1, tolerance_));
          bodyPairMap[jp] = bodyPairCollisions_.back();
        }
        bodyPairMap[jp]->addCollisionPair (
            CollisionObjectConstPtr_t (new pinocchio::CollisionObject(robot, cp.first )),
            CollisionObjectConstPtr_t (new pinocchio::CollisionObject(robot, cp.second)));
      }
    }
  } // namespace core
} // namespace hpp
<|endoftext|>


<commit_before>#include "CommonData.hpp"
#include "Config.hpp"
#include "FlagStatus.hpp"
#include "IOLogWrapper.hpp"
#include "KeyCodeModifierFlagPairs.hpp"
#include "ModifierName.hpp"

namespace org_pqrs_Karabiner {
FlagStatus globalFlagStatus_;

FlagStatus&
FlagStatus::globalFlagStatus(void) {
  return globalFlagStatus_;
}

void
FlagStatus::Item::initialize(ModifierFlag f) {
  flag_ = f;
  count_ = 0;
  temporary_count_ = 0;
  lock_count_ = 0;
  negative_lock_count_ = 0;
  sticky_count_ = 0;
}

void
FlagStatus::Item::set(void) {
  temporary_count_ = 0;
}

void
FlagStatus::Item::set(KeyCode key, Flags flags) {
  temporary_count_ = 0;

  // ------------------------------------------------------------
  if (key != flag_.getKeyCode()) return;

  // ------------------------------------------------------------
  if (flag_ == ModifierFlag::CAPSLOCK) {
    if (flags.isOn(flag_)) {
      lock_count_ = 1;
    } else {
      lock_count_ = 0;
    }

  } else {
    if (flags.isOn(flag_)) {
      increase();
    } else {
      decrease();

      // Some keyboards sometimes drop keyup events for modifiers and modifiers will be stuck.
      // So, set count_ zero for this case.
      if (Config::get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_general_workaround_stuck_keyboards)) {
        count_ = 0;
      }
    }
  }
}

void
FlagStatus::Item::reset(void) {
  count_ = 0;
  temporary_count_ = 0;
  lazy_count_ = 0;
  lazy_enabled_ = false;

  /*
       preserve lock_count, negative_lock_count_ and sticky_count_.

       FlagStatus::reset is called when PressingPhysicalKeys is empty,
       so we need remember the status of CapsLock.
     */
}

void
FlagStatus::Item::increase(void) {
  if (flag_ == ModifierFlag::CAPSLOCK) {
    lock_count_ = !lock_count_;
  } else {
    ++count_;
  }
}

void
FlagStatus::Item::decrease(void) {
  if (flag_ == ModifierFlag::CAPSLOCK) {
    // do nothing (toggle at Item::increase).
  } else {
    --count_;
  }
}

// ----------------------------------------------------------------------
void
FlagStatus::initialize(void) {
  item_.clear();

  auto& pairs = KeyCodeModifierFlagPairs::getPairs();
  for (size_t i = 0; i < pairs.size(); ++i) {
    item_.push_back(Item());
    item_.back().initialize(pairs[i].getModifierFlag());
  }
}

FlagStatus::FlagStatus(void) {
  initialize();
}

FlagStatus::FlagStatus(Flags flags) {
  initialize();

  for (size_t i = 0; i < item_.size(); ++i) {
    if (flags.isOn(item_[i].flag_)) {
      item_[i].increase();
    }
  }
}

void
FlagStatus::set(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].set();
  }
}

void
FlagStatus::set(KeyCode key, Flags flags) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].set(key, flags);
  }
}

void
FlagStatus::reset(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].reset();
  }
}

bool
FlagStatus::isOn(ModifierFlag modifierFlag) const {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].flag_ == modifierFlag) {
      return item_[i].sum(true) > 0;
    }
  }
  return false;
}

bool
FlagStatus::isOn(const Vector_ModifierFlag& modifierFlags) const {
  bool strict = false;

  for (size_t i = 0; i < modifierFlags.size(); ++i) {
    if (modifierFlags[i] == ModifierFlag::ZERO) continue;

    if (modifierFlags[i] == ModifierFlag::NONE) {
      strict = true;
    } else {
      if (!isOn(modifierFlags[i])) return false;
    }
  }

  // If modifierFlags contains ModifierFlag::NONE,
  // return false when unspecified modifierflag is pressed.
  if (strict) {
    for (size_t i = 0; i < item_.size(); ++i) {
      if (item_[i].sum(true) > 0 &&
          !modifierFlags.is_include(item_[i].flag_)) {
        return false;
      }
    }
  }

  return true;
}

bool
FlagStatus::isLocked(const Vector_ModifierFlag& modifierFlags) const {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].flag_ == ModifierFlag::ZERO) continue;
    if (item_[i].flag_ == ModifierFlag::NONE) continue;

    if (modifierFlags.is_include(item_[i].flag_) &&
        item_[i].lock_count_ <= 0) {
      return false;
    }
  }
  return true;
}

bool
FlagStatus::isStuck(const Vector_ModifierFlag& modifierFlags) const {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].flag_ == ModifierFlag::ZERO) continue;
    if (item_[i].flag_ == ModifierFlag::NONE) continue;

    if (modifierFlags.is_include(item_[i].flag_) &&
        item_[i].sticky_count_ <= 0) {
      return false;
    }
  }
  return true;
}

Flags
FlagStatus::makeFlags(void) const {
  Flags flags;
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].sum(false) > 0) {
      flags.add(item_[i].flag_);
    }
  }
  return flags;
}

ModifierFlag
FlagStatus::getFlag(size_t index) const {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (i == index) {
      return item_[i].flag_;
    }
  }
  return ModifierFlag::ZERO;
}

// ------------------------------------------------------------
#define DEFINE_METHODS(METHOD)                                                                   \
  void FlagStatus::METHOD(ModifierFlag modifierFlag) {                                           \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlag == item_[i].flag_) {                                                      \
        item_[i].METHOD();                                                                       \
      }                                                                                \
    }                                                                                \
  }                                                                                \
  void FlagStatus::METHOD(ModifierFlag modifierFlag, const Vector_ModifierFlag& modifierFlags) { \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlag == item_[i].flag_ || modifierFlags.is_include(item_[i].flag_)) {          \
        item_[i].METHOD();                                                                       \
      }                                                                                \
    }                                                                                \
  }                                                                                \
  void FlagStatus::METHOD(const Vector_ModifierFlag& modifierFlags) {                            \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlags.is_include(item_[i].flag_)) {                                            \
        item_[i].METHOD();                                                                       \
      }                                                                                \
    }                                                                                \
  }

DEFINE_METHODS(increase)
DEFINE_METHODS(decrease)
DEFINE_METHODS(temporary_increase)
DEFINE_METHODS(temporary_decrease)
DEFINE_METHODS(lazy_increase)
DEFINE_METHODS(lazy_decrease)
#undef DEFINE_METHODS

#define DEFINE_METHODS(METHOD)                                                                   \
  void FlagStatus::METHOD(ModifierFlag modifierFlag) {                                           \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlag == item_[i].flag_) {                                                      \
        item_[i].METHOD();                                                                       \
        updateStatusMessage();                                                                   \
      }                                                                                \
    }                                                                                \
  }                                                                                \
  void FlagStatus::METHOD(ModifierFlag modifierFlag, const Vector_ModifierFlag& modifierFlags) { \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlag == item_[i].flag_ || modifierFlags.is_include(item_[i].flag_)) {          \
        item_[i].METHOD();                                                                       \
        updateStatusMessage();                                                                   \
      }                                                                                \
    }                                                                                \
  }                                                                                \
  void FlagStatus::METHOD(const Vector_ModifierFlag& modifierFlags) {                            \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlags.is_include(item_[i].flag_)) {                                            \
        item_[i].METHOD();                                                                       \
        updateStatusMessage();                                                                   \
      }                                                                                \
    }                                                                                \
  }

DEFINE_METHODS(lock_increase)
DEFINE_METHODS(lock_decrease)
DEFINE_METHODS(lock_toggle)
DEFINE_METHODS(negative_lock_increase)
DEFINE_METHODS(negative_lock_decrease)
DEFINE_METHODS(negative_lock_toggle)
DEFINE_METHODS(sticky_increase)
DEFINE_METHODS(sticky_decrease)
DEFINE_METHODS(sticky_toggle)
#undef DEFINE_METHODS

#define STICKY_ACTIVE_MODIFIERS_METHOD(METHOD)  \
  {                                             \
    for (size_t i = 0; i < item_.size(); ++i) { \
      if (item_[i].sum(true) > 0) {             \
        item_[i].METHOD();                      \
      }                                         \
    }                                           \
    updateStatusMessage();                      \
  }

void FlagStatus::sticky_active_modifiers_toggle(void) { STICKY_ACTIVE_MODIFIERS_METHOD(sticky_toggle); }
void FlagStatus::sticky_active_modifiers_increase(void) { STICKY_ACTIVE_MODIFIERS_METHOD(sticky_increase); }
void FlagStatus::sticky_active_modifiers_decrease(void) { STICKY_ACTIVE_MODIFIERS_METHOD(sticky_decrease); }
#undef STICKY_ACTIVE_MODIFIERS_METHOD

void
FlagStatus::sticky_clear(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].sticky_decrease();
  }
  updateStatusMessage();
}

void
FlagStatus::lock_clear(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].lock_count_) {
      item_[i].lock_decrease();
    }
  }
  updateStatusMessage();
}

void
FlagStatus::negative_lock_clear(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].negative_lock_count_) {
      item_[i].negative_lock_decrease();
    }
  }
  updateStatusMessage();
}

void
FlagStatus::lazy_enable(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].lazy_enable();
  }
}

void
FlagStatus::lazy_disable_if_off(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].lazy_disable_if_off();
  }
}

void
FlagStatus::subtract(const FlagStatus& other, Vector_ModifierFlag& modifierFlags) const {
  modifierFlags.clear();

  if (item_.size() == other.item_.size()) {
    for (size_t i = 0; i < item_.size(); ++i) {
      int sum1 = item_[i].sum(true);
      int sum2 = other.item_[i].sum(true);
      if (sum1 > sum2) {
        for (int j = 0; j < sum1 - sum2; ++j) {
          modifierFlags.push_back(item_[i].flag_);
        }
      }
    }
  }
}

void
FlagStatus::updateStatusMessage(unsigned int statusMessageIndex) {
  CommonData::clear_statusmessage(statusMessageIndex);

  for (size_t i = 0; i < item_.size(); ++i) {
    // Skip caps lock.
    if (item_[i].flag_ == ModifierFlag::CAPSLOCK) continue;

    const char* name = ModifierName::getName(item_[i].flag_);
    if (name) {
      switch (statusMessageIndex) {
      case BRIDGE_USERCLIENT_STATUS_MESSAGE_MODIFIER_LOCK:
        if (item_[i].negative_lock_count_ > 0) {
          CommonData::append_statusmessage(statusMessageIndex, "-");
          CommonData::append_statusmessage(statusMessageIndex, name);
          CommonData::append_statusmessage(statusMessageIndex, " ");
        } else if (item_[i].lock_count_ > 0) {
          CommonData::append_statusmessage(statusMessageIndex, name);
          CommonData::append_statusmessage(statusMessageIndex, " ");
        }
        break;

      case BRIDGE_USERCLIENT_STATUS_MESSAGE_MODIFIER_STICKY:
        if (item_[i].sticky_count_ > 0) {
          CommonData::append_statusmessage(statusMessageIndex, name);
          CommonData::append_statusmessage(statusMessageIndex, " ");
        }
        break;
      }
    }
  }
}

void
FlagStatus::updateStatusMessage(void) {
  int indexes[] = {
      BRIDGE_USERCLIENT_STATUS_MESSAGE_MODIFIER_LOCK,
      BRIDGE_USERCLIENT_STATUS_MESSAGE_MODIFIER_STICKY,
  };
  for (size_t i = 0; i < sizeof(indexes) / sizeof(indexes[0]); ++i) {
    int idx = indexes[i];

    static char previousMessage[BRIDGE_USERCLIENT_STATUS_MESSAGE_MAXLEN];
    strlcat(previousMessage, CommonData::get_statusmessage(idx), sizeof(previousMessage));

    updateStatusMessage(idx);

    if (strcmp(CommonData::get_statusmessage(idx), previousMessage) != 0) {
      CommonData::send_notification_statusmessage(idx);
    }
  }
}
}
<commit_msg>revert general.workaround_stuck_keyboards<commit_after>#include "CommonData.hpp"
#include "FlagStatus.hpp"
#include "IOLogWrapper.hpp"
#include "KeyCodeModifierFlagPairs.hpp"
#include "ModifierName.hpp"

namespace org_pqrs_Karabiner {
FlagStatus globalFlagStatus_;

FlagStatus&
FlagStatus::globalFlagStatus(void) {
  return globalFlagStatus_;
}

void
FlagStatus::Item::initialize(ModifierFlag f) {
  flag_ = f;
  count_ = 0;
  temporary_count_ = 0;
  lock_count_ = 0;
  negative_lock_count_ = 0;
  sticky_count_ = 0;
}

void
FlagStatus::Item::set(void) {
  temporary_count_ = 0;
}

void
FlagStatus::Item::set(KeyCode key, Flags flags) {
  temporary_count_ = 0;

  // ------------------------------------------------------------
  if (key != flag_.getKeyCode()) return;

  // ------------------------------------------------------------
  if (flag_ == ModifierFlag::CAPSLOCK) {
    if (flags.isOn(flag_)) {
      lock_count_ = 1;
    } else {
      lock_count_ = 0;
    }

  } else {
    if (flags.isOn(flag_)) {
      increase();
    } else {
      decrease();
    }
  }
}

void
FlagStatus::Item::reset(void) {
  count_ = 0;
  temporary_count_ = 0;
  lazy_count_ = 0;
  lazy_enabled_ = false;

  /*
       preserve lock_count, negative_lock_count_ and sticky_count_.

       FlagStatus::reset is called when PressingPhysicalKeys is empty,
       so we need remember the status of CapsLock.
     */
}

void
FlagStatus::Item::increase(void) {
  if (flag_ == ModifierFlag::CAPSLOCK) {
    lock_count_ = !lock_count_;
  } else {
    ++count_;
  }
}

void
FlagStatus::Item::decrease(void) {
  if (flag_ == ModifierFlag::CAPSLOCK) {
    // do nothing (toggle at Item::increase).
  } else {
    --count_;
  }
}

// ----------------------------------------------------------------------
void
FlagStatus::initialize(void) {
  item_.clear();

  auto& pairs = KeyCodeModifierFlagPairs::getPairs();
  for (size_t i = 0; i < pairs.size(); ++i) {
    item_.push_back(Item());
    item_.back().initialize(pairs[i].getModifierFlag());
  }
}

FlagStatus::FlagStatus(void) {
  initialize();
}

FlagStatus::FlagStatus(Flags flags) {
  initialize();

  for (size_t i = 0; i < item_.size(); ++i) {
    if (flags.isOn(item_[i].flag_)) {
      item_[i].increase();
    }
  }
}

void
FlagStatus::set(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].set();
  }
}

void
FlagStatus::set(KeyCode key, Flags flags) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].set(key, flags);
  }
}

void
FlagStatus::reset(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].reset();
  }
}

bool
FlagStatus::isOn(ModifierFlag modifierFlag) const {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].flag_ == modifierFlag) {
      return item_[i].sum(true) > 0;
    }
  }
  return false;
}

bool
FlagStatus::isOn(const Vector_ModifierFlag& modifierFlags) const {
  bool strict = false;

  for (size_t i = 0; i < modifierFlags.size(); ++i) {
    if (modifierFlags[i] == ModifierFlag::ZERO) continue;

    if (modifierFlags[i] == ModifierFlag::NONE) {
      strict = true;
    } else {
      if (!isOn(modifierFlags[i])) return false;
    }
  }

  // If modifierFlags contains ModifierFlag::NONE,
  // return false when unspecified modifierflag is pressed.
  if (strict) {
    for (size_t i = 0; i < item_.size(); ++i) {
      if (item_[i].sum(true) > 0 &&
          !modifierFlags.is_include(item_[i].flag_)) {
        return false;
      }
    }
  }

  return true;
}

bool
FlagStatus::isLocked(const Vector_ModifierFlag& modifierFlags) const {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].flag_ == ModifierFlag::ZERO) continue;
    if (item_[i].flag_ == ModifierFlag::NONE) continue;

    if (modifierFlags.is_include(item_[i].flag_) &&
        item_[i].lock_count_ <= 0) {
      return false;
    }
  }
  return true;
}

bool
FlagStatus::isStuck(const Vector_ModifierFlag& modifierFlags) const {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].flag_ == ModifierFlag::ZERO) continue;
    if (item_[i].flag_ == ModifierFlag::NONE) continue;

    if (modifierFlags.is_include(item_[i].flag_) &&
        item_[i].sticky_count_ <= 0) {
      return false;
    }
  }
  return true;
}

Flags
FlagStatus::makeFlags(void) const {
  Flags flags;
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].sum(false) > 0) {
      flags.add(item_[i].flag_);
    }
  }
  return flags;
}

ModifierFlag
FlagStatus::getFlag(size_t index) const {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (i == index) {
      return item_[i].flag_;
    }
  }
  return ModifierFlag::ZERO;
}

// ------------------------------------------------------------
#define DEFINE_METHODS(METHOD)                                                                   \
  void FlagStatus::METHOD(ModifierFlag modifierFlag) {                                           \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlag == item_[i].flag_) {                                                      \
        item_[i].METHOD();                                                                       \
      }                                                                                \
    }                                                                                \
  }                                                                                \
  void FlagStatus::METHOD(ModifierFlag modifierFlag, const Vector_ModifierFlag& modifierFlags) { \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlag == item_[i].flag_ || modifierFlags.is_include(item_[i].flag_)) {          \
        item_[i].METHOD();                                                                       \
      }                                                                                \
    }                                                                                \
  }                                                                                \
  void FlagStatus::METHOD(const Vector_ModifierFlag& modifierFlags) {                            \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlags.is_include(item_[i].flag_)) {                                            \
        item_[i].METHOD();                                                                       \
      }                                                                                \
    }                                                                                \
  }

DEFINE_METHODS(increase)
DEFINE_METHODS(decrease)
DEFINE_METHODS(temporary_increase)
DEFINE_METHODS(temporary_decrease)
DEFINE_METHODS(lazy_increase)
DEFINE_METHODS(lazy_decrease)
#undef DEFINE_METHODS

#define DEFINE_METHODS(METHOD)                                                                   \
  void FlagStatus::METHOD(ModifierFlag modifierFlag) {                                           \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlag == item_[i].flag_) {                                                      \
        item_[i].METHOD();                                                                       \
        updateStatusMessage();                                                                   \
      }                                                                                \
    }                                                                                \
  }                                                                                \
  void FlagStatus::METHOD(ModifierFlag modifierFlag, const Vector_ModifierFlag& modifierFlags) { \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlag == item_[i].flag_ || modifierFlags.is_include(item_[i].flag_)) {          \
        item_[i].METHOD();                                                                       \
        updateStatusMessage();                                                                   \
      }                                                                                \
    }                                                                                \
  }                                                                                \
  void FlagStatus::METHOD(const Vector_ModifierFlag& modifierFlags) {                            \
    for (size_t i = 0; i < item_.size(); ++i) {                                                  \
      if (modifierFlags.is_include(item_[i].flag_)) {                                            \
        item_[i].METHOD();                                                                       \
        updateStatusMessage();                                                                   \
      }                                                                                \
    }                                                                                \
  }

DEFINE_METHODS(lock_increase)
DEFINE_METHODS(lock_decrease)
DEFINE_METHODS(lock_toggle)
DEFINE_METHODS(negative_lock_increase)
DEFINE_METHODS(negative_lock_decrease)
DEFINE_METHODS(negative_lock_toggle)
DEFINE_METHODS(sticky_increase)
DEFINE_METHODS(sticky_decrease)
DEFINE_METHODS(sticky_toggle)
#undef DEFINE_METHODS

#define STICKY_ACTIVE_MODIFIERS_METHOD(METHOD)  \
  {                                             \
    for (size_t i = 0; i < item_.size(); ++i) { \
      if (item_[i].sum(true) > 0) {             \
        item_[i].METHOD();                      \
      }                                         \
    }                                           \
    updateStatusMessage();                      \
  }

void FlagStatus::sticky_active_modifiers_toggle(void) { STICKY_ACTIVE_MODIFIERS_METHOD(sticky_toggle); }
void FlagStatus::sticky_active_modifiers_increase(void) { STICKY_ACTIVE_MODIFIERS_METHOD(sticky_increase); }
void FlagStatus::sticky_active_modifiers_decrease(void) { STICKY_ACTIVE_MODIFIERS_METHOD(sticky_decrease); }
#undef STICKY_ACTIVE_MODIFIERS_METHOD

void
FlagStatus::sticky_clear(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].sticky_decrease();
  }
  updateStatusMessage();
}

void
FlagStatus::lock_clear(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].lock_count_) {
      item_[i].lock_decrease();
    }
  }
  updateStatusMessage();
}

void
FlagStatus::negative_lock_clear(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    if (item_[i].negative_lock_count_) {
      item_[i].negative_lock_decrease();
    }
  }
  updateStatusMessage();
}

void
FlagStatus::lazy_enable(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].lazy_enable();
  }
}

void
FlagStatus::lazy_disable_if_off(void) {
  for (size_t i = 0; i < item_.size(); ++i) {
    item_[i].lazy_disable_if_off();
  }
}

void
FlagStatus::subtract(const FlagStatus& other, Vector_ModifierFlag& modifierFlags) const {
  modifierFlags.clear();

  if (item_.size() == other.item_.size()) {
    for (size_t i = 0; i < item_.size(); ++i) {
      int sum1 = item_[i].sum(true);
      int sum2 = other.item_[i].sum(true);
      if (sum1 > sum2) {
        for (int j = 0; j < sum1 - sum2; ++j) {
          modifierFlags.push_back(item_[i].flag_);
        }
      }
    }
  }
}

void
FlagStatus::updateStatusMessage(unsigned int statusMessageIndex) {
  CommonData::clear_statusmessage(statusMessageIndex);

  for (size_t i = 0; i < item_.size(); ++i) {
    // Skip caps lock.
    if (item_[i].flag_ == ModifierFlag::CAPSLOCK) continue;

    const char* name = ModifierName::getName(item_[i].flag_);
    if (name) {
      switch (statusMessageIndex) {
      case BRIDGE_USERCLIENT_STATUS_MESSAGE_MODIFIER_LOCK:
        if (item_[i].negative_lock_count_ > 0) {
          CommonData::append_statusmessage(statusMessageIndex, "-");
          CommonData::append_statusmessage(statusMessageIndex, name);
          CommonData::append_statusmessage(statusMessageIndex, " ");
        } else if (item_[i].lock_count_ > 0) {
          CommonData::append_statusmessage(statusMessageIndex, name);
          CommonData::append_statusmessage(statusMessageIndex, " ");
        }
        break;

      case BRIDGE_USERCLIENT_STATUS_MESSAGE_MODIFIER_STICKY:
        if (item_[i].sticky_count_ > 0) {
          CommonData::append_statusmessage(statusMessageIndex, name);
          CommonData::append_statusmessage(statusMessageIndex, " ");
        }
        break;
      }
    }
  }
}

void
FlagStatus::updateStatusMessage(void) {
  int indexes[] = {
      BRIDGE_USERCLIENT_STATUS_MESSAGE_MODIFIER_LOCK,
      BRIDGE_USERCLIENT_STATUS_MESSAGE_MODIFIER_STICKY,
  };
  for (size_t i = 0; i < sizeof(indexes) / sizeof(indexes[0]); ++i) {
    int idx = indexes[i];

    static char previousMessage[BRIDGE_USERCLIENT_STATUS_MESSAGE_MAXLEN];
    strlcat(previousMessage, CommonData::get_statusmessage(idx), sizeof(previousMessage));

    updateStatusMessage(idx);

    if (strcmp(CommonData::get_statusmessage(idx), previousMessage) != 0) {
      CommonData::send_notification_statusmessage(idx);
    }
  }
}
}
<|endoftext|>


<commit_before>/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// See docs in ../ops/array_ops.cc.

#include <unordered_set>

#include <vector>
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/kernels/bounds_check.h"

namespace tensorflow {

class ShapeOp : public OpKernel {
 public:
  explicit ShapeOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext* ctx) override {
    const Tensor& inp = ctx->input(0);
    const int rank = inp.dims();
    Tensor* out = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, TensorShape({rank}), &out));
    auto vec = out->vec<int32>();
    // TODO(dga): support int64.  b/28119922.
    for (int i = 0; i < rank; ++i) {
      int64 dim_size = inp.dim_size(i);
      OP_REQUIRES(
          ctx, FastBoundsCheck(dim_size, std::numeric_limits<int32>::max()),
          errors::InvalidArgument("Shape does not support tensors > int32max",
                                  " but dim ", i, " is ", dim_size));
      vec(i) = static_cast<int32>(dim_size);
    }
  }

  bool IsExpensive() override { return false; }
};
REGISTER_KERNEL_BUILDER(Name("Shape").Device(DEVICE_CPU).HostMemory("output"),
                        ShapeOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                         \
  REGISTER_KERNEL_BUILDER(Name("Shape")                   \
                              .Device(DEVICE_GPU)         \
                              .HostMemory("output")       \
                              .TypeConstraint<type>("T"), \
                          ShapeOp)
TF_CALL_REAL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

// A special GPU kernel for int32.
// TODO(b/25387198): Also enable int32 in device memory. This kernel
// registration requires all int32 inputs and outputs to be in host memory.
REGISTER_KERNEL_BUILDER(Name("Shape")
                            .Device(DEVICE_GPU)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        ShapeOp);
#endif

class ShapeNOp : public OpKernel {
 public:
  explicit ShapeNOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext* ctx) override {
    for (int i = 0; i < ctx->num_inputs(); ++i) {
      auto shape = ctx->input(i).shape();
      const int dims = shape.dims();
      Tensor* out = nullptr;
      OP_REQUIRES_OK(ctx, ctx->allocate_output(i, {dims}, &out));
      auto vec = out->vec<int32>();

      // TODO(dga): support int64.  b/28119922.
      for (int j = 0; j < dims; ++j) {
        int64 dim_size = shape.dim_size(j);
        OP_REQUIRES(
            ctx, FastBoundsCheck(dim_size, std::numeric_limits<int32>::max()),
            errors::InvalidArgument("Shape does not support tensors > int32max",
                                    " but shape ", i, " dim ", j, " is ",
                                    dim_size));
        vec(j) = static_cast<int32>(dim_size);
      }
    }
  }

  bool IsExpensive() override { return false; }
};
REGISTER_KERNEL_BUILDER(Name("ShapeN").Device(DEVICE_CPU).HostMemory("output"),
                        ShapeNOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                         \
  REGISTER_KERNEL_BUILDER(Name("ShapeN")                  \
                              .Device(DEVICE_GPU)         \
                              .HostMemory("output")       \
                              .TypeConstraint<type>("T"), \
                          ShapeNOp)
TF_CALL_REAL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

// A special GPU kernel for int32.
// TODO(b/25387198): Also enable int32 in device memory. This kernel
// registration requires all int32 inputs and outputs to be in host memory.
REGISTER_KERNEL_BUILDER(Name("ShapeN")
                            .Device(DEVICE_GPU)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        ShapeNOp);
#endif

class RankOp : public OpKernel {
 public:
  explicit RankOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext* ctx) override {
    const Tensor& inp = ctx->input(0);
    const int rank = inp.dims();
    Tensor* out = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, TensorShape({}), &out));
    out->scalar<int32>()() = rank;
  }

  bool IsExpensive() override { return false; }
};
REGISTER_KERNEL_BUILDER(Name("Rank").Device(DEVICE_CPU).HostMemory("output"),
                        RankOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                        \
  REGISTER_KERNEL_BUILDER(Name("Rank")                   \
                              .Device(DEVICE_GPU)        \
                              .TypeConstraint<type>("T") \
                              .HostMemory("output"),     \
                          RankOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

// A special GPU kernel for int32 and bool.
// TODO(b/25387198): Also enable int32 in device memory. This kernel
// registration requires all int32 inputs and outputs to be in host memory.
REGISTER_KERNEL_BUILDER(Name("Rank")
                            .Device(DEVICE_GPU)
                            .TypeConstraint<int32>("T")
                            .HostMemory("input")
                            .HostMemory("output"),
                        RankOp);

REGISTER_KERNEL_BUILDER(Name("Rank")
                            .Device(DEVICE_GPU)
                            .TypeConstraint<bool>("T")
                            .HostMemory("input")
                            .HostMemory("output"),
                        RankOp);
#endif

class SizeOp : public OpKernel {
 public:
  explicit SizeOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext* ctx) override {
    const Tensor& inp = ctx->input(0);
    const int64 size = inp.NumElements();
    Tensor* out = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, TensorShape({}), &out));
    OP_REQUIRES(ctx, FastBoundsCheck(size, std::numeric_limits<int32>::max()),
                errors::InvalidArgument("Size does not work for tensors > "
                                        "int32 max."));
    // TODO(josh11b): switch output to int64?  (b/28119922)
    out->scalar<int32>()() = static_cast<int32>(size);
  }

  bool IsExpensive() override { return false; }
};
REGISTER_KERNEL_BUILDER(Name("Size").Device(DEVICE_CPU).HostMemory("output"),
                        SizeOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                        \
  REGISTER_KERNEL_BUILDER(Name("Size")                   \
                              .Device(DEVICE_GPU)        \
                              .TypeConstraint<type>("T") \
                              .HostMemory("output"),     \
                          SizeOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

// A special GPU kernel for int32.
// TODO(b/25387198): Also enable int32 in device memory. This kernel
// registration requires all int32 inputs and outputs to be in host memory.
REGISTER_KERNEL_BUILDER(Name("Size")
                            .Device(DEVICE_GPU)
                            .TypeConstraint<int32>("T")
                            .HostMemory("input")
                            .HostMemory("output"),
                        SizeOp);
#endif

class ExpandDimsOp : public OpKernel {
 public:
  explicit ExpandDimsOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext* ctx) override {
    int dim = ctx->input(1).flat<int>()(0);
    OP_REQUIRES(
        ctx, (dim >= -1 - ctx->input(0).dims() && dim <= ctx->input(0).dims()),
        errors::InvalidArgument("Tried to expand dim index ", dim,
                                " for tensor with ", ctx->input(0).dims(),
                                " dimensions."));

    auto existing_dims = ctx->input(0).shape().dim_sizes();
    // Safe - # elements in tensor dims bounded.
    const int existing_dims_size = static_cast<int>(existing_dims.size());
    std::vector<int64> new_shape(existing_dims_size);
    for (size_t i = 0; i < new_shape.size(); ++i) {
      new_shape[i] = existing_dims[i];
    }

    // We emulate numpy's interpretation of the dim axis when
    // -input.dims() >= dim <= input.dims().
    if (dim < 0) {
      dim += existing_dims.size() + 1;
    }

    // Clamp to the end if needed.
    dim = std::min<int32>(dim, existing_dims_size);
    new_shape.emplace(new_shape.begin() + dim, 1);
    const TensorShape output_shape(new_shape);

    Tensor* output = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, {0}, &output));
    if (!output->CopyFrom(ctx->input(0), output_shape)) {
      // This should never happen, since the sizes of the input and output
      // should always be the same (we only expand the dimension with 1).
      ctx->SetStatus(
          errors::Internal("Could not expand dimension with input shape ",
                           ctx->input(0).shape().DebugString(),
                           " and output shape ", output_shape.DebugString()));
    }
  }
};
REGISTER_KERNEL_BUILDER(Name("ExpandDims").Device(DEVICE_CPU).HostMemory("dim"),
                        ExpandDimsOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                        \
  REGISTER_KERNEL_BUILDER(Name("ExpandDims")             \
                              .Device(DEVICE_GPU)        \
                              .TypeConstraint<type>("T") \
                              .HostMemory("dim"),        \
                          ExpandDimsOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

REGISTER_KERNEL_BUILDER(Name("ExpandDims")
                            .Device(DEVICE_GPU)
                            .TypeConstraint<int32>("T")
                            .HostMemory("input")
                            .HostMemory("dim")
                            .HostMemory("output"),
                        ExpandDimsOp);
#endif

class SqueezeOp : public OpKernel {
 public:
  explicit SqueezeOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    std::vector<int32> squeeze_dims;
    OP_REQUIRES_OK(ctx, ctx->GetAttr("squeeze_dims", &squeeze_dims));
    squeeze_dims_.insert(squeeze_dims.begin(), squeeze_dims.end());
  }

  void Compute(OpKernelContext* ctx) override {
    auto existing_dims = ctx->input(0).shape().dim_sizes();
    const int existing_dims_size = static_cast<int>(existing_dims.size());
    std::vector<int64> new_shape;

    std::unordered_set<int32> wrapped_squeeze_dims;
    wrapped_squeeze_dims.reserve(squeeze_dims_.size());
    // Validate squeeze dims against the input.
    for (int32 dim : squeeze_dims_) {
      OP_REQUIRES(
          ctx, (dim >= -ctx->input(0).dims() && dim < ctx->input(0).dims()),
          errors::InvalidArgument("Tried to squeeze dim index ", dim,
                                  " for tensor with ", ctx->input(0).dims(),
                                  " dimensions."));
      // If dim is < 0, we wrap around (-1 means the last element).
      if (dim < 0) {
        dim = existing_dims_size + dim;
      }

      wrapped_squeeze_dims.insert(dim);
    }

    for (int i = 0; i < existing_dims_size; ++i) {
      auto existing_dim = existing_dims[i];

      // If squeeze_set is non-empty, only squeeze those dimensions.
      if (!wrapped_squeeze_dims.empty()) {
        if (wrapped_squeeze_dims.count(i) > 0) {
          OP_REQUIRES(ctx, existing_dim == 1,
                      errors::InvalidArgument("Tried to explicitly squeeze "
                                              "dimension ",
                                              i, " but dimension was not 1: ",
                                              existing_dim));
        } else {
          // This dimension is not being squeezed.
          new_shape.push_back(existing_dim);
        }
      } else {
        // Copy over all non-1-length dimensions.
        if (existing_dim != 1) {
          new_shape.push_back(existing_dim);
        }
      }
    }

    const TensorShape output_shape(new_shape);
    Tensor* output = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, {0}, &output));
    if (!output->CopyFrom(ctx->input(0), output_shape)) {
      // This should never happen, since the sizes of the input and
      // output should always be the same.
      ctx->SetStatus(errors::Internal("Could not squeeze input with shape ",
                                      ctx->input(0).shape().DebugString(),
                                      " and output shape ",
                                      output_shape.DebugString()));
    }
  }

 private:
  std::unordered_set<int32> squeeze_dims_;
};

REGISTER_KERNEL_BUILDER(Name("Squeeze").Device(DEVICE_CPU), SqueezeOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                                   \
  REGISTER_KERNEL_BUILDER(                                          \
      Name("Squeeze").Device(DEVICE_GPU).TypeConstraint<type>("T"), \
      SqueezeOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

// A special GPU kernel for int32.
// TODO(b/25387198): Also enable int32 in device memory. This kernel
// registration requires all int32 inputs and outputs to be in host memory.
REGISTER_KERNEL_BUILDER(Name("Squeeze")
                            .Device(DEVICE_GPU)
                            .TypeConstraint<int32>("T")
                            .HostMemory("input")
                            .HostMemory("output"),
                        SqueezeOp);
#endif

}  // namespace tensorflow
<commit_msg>Mark the ExpandDimOp and the SqueezeOp as non expensive Change: 128892723<commit_after>/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// See docs in ../ops/array_ops.cc.

#include <unordered_set>

#include <vector>
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/kernels/bounds_check.h"

namespace tensorflow {

class ShapeOp : public OpKernel {
 public:
  explicit ShapeOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext* ctx) override {
    const Tensor& inp = ctx->input(0);
    const int rank = inp.dims();
    Tensor* out = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, TensorShape({rank}), &out));
    auto vec = out->vec<int32>();
    // TODO(dga): support int64.  b/28119922.
    for (int i = 0; i < rank; ++i) {
      int64 dim_size = inp.dim_size(i);
      OP_REQUIRES(
          ctx, FastBoundsCheck(dim_size, std::numeric_limits<int32>::max()),
          errors::InvalidArgument("Shape does not support tensors > int32max",
                                  " but dim ", i, " is ", dim_size));
      vec(i) = static_cast<int32>(dim_size);
    }
  }

  bool IsExpensive() override { return false; }
};
REGISTER_KERNEL_BUILDER(Name("Shape").Device(DEVICE_CPU).HostMemory("output"),
                        ShapeOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                         \
  REGISTER_KERNEL_BUILDER(Name("Shape")                   \
                              .Device(DEVICE_GPU)         \
                              .HostMemory("output")       \
                              .TypeConstraint<type>("T"), \
                          ShapeOp)
TF_CALL_REAL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

// A special GPU kernel for int32.
// TODO(b/25387198): Also enable int32 in device memory. This kernel
// registration requires all int32 inputs and outputs to be in host memory.
REGISTER_KERNEL_BUILDER(Name("Shape")
                            .Device(DEVICE_GPU)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        ShapeOp);
#endif

class ShapeNOp : public OpKernel {
 public:
  explicit ShapeNOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext* ctx) override {
    for (int i = 0; i < ctx->num_inputs(); ++i) {
      auto shape = ctx->input(i).shape();
      const int dims = shape.dims();
      Tensor* out = nullptr;
      OP_REQUIRES_OK(ctx, ctx->allocate_output(i, {dims}, &out));
      auto vec = out->vec<int32>();

      // TODO(dga): support int64.  b/28119922.
      for (int j = 0; j < dims; ++j) {
        int64 dim_size = shape.dim_size(j);
        OP_REQUIRES(
            ctx, FastBoundsCheck(dim_size, std::numeric_limits<int32>::max()),
            errors::InvalidArgument("Shape does not support tensors > int32max",
                                    " but shape ", i, " dim ", j, " is ",
                                    dim_size));
        vec(j) = static_cast<int32>(dim_size);
      }
    }
  }

  bool IsExpensive() override { return false; }
};
REGISTER_KERNEL_BUILDER(Name("ShapeN").Device(DEVICE_CPU).HostMemory("output"),
                        ShapeNOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                         \
  REGISTER_KERNEL_BUILDER(Name("ShapeN")                  \
                              .Device(DEVICE_GPU)         \
                              .HostMemory("output")       \
                              .TypeConstraint<type>("T"), \
                          ShapeNOp)
TF_CALL_REAL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

// A special GPU kernel for int32.
// TODO(b/25387198): Also enable int32 in device memory. This kernel
// registration requires all int32 inputs and outputs to be in host memory.
REGISTER_KERNEL_BUILDER(Name("ShapeN")
                            .Device(DEVICE_GPU)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        ShapeNOp);
#endif

class RankOp : public OpKernel {
 public:
  explicit RankOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext* ctx) override {
    const Tensor& inp = ctx->input(0);
    const int rank = inp.dims();
    Tensor* out = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, TensorShape({}), &out));
    out->scalar<int32>()() = rank;
  }

  bool IsExpensive() override { return false; }
};
REGISTER_KERNEL_BUILDER(Name("Rank").Device(DEVICE_CPU).HostMemory("output"),
                        RankOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                        \
  REGISTER_KERNEL_BUILDER(Name("Rank")                   \
                              .Device(DEVICE_GPU)        \
                              .TypeConstraint<type>("T") \
                              .HostMemory("output"),     \
                          RankOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

// A special GPU kernel for int32 and bool.
// TODO(b/25387198): Also enable int32 in device memory. This kernel
// registration requires all int32 inputs and outputs to be in host memory.
REGISTER_KERNEL_BUILDER(Name("Rank")
                            .Device(DEVICE_GPU)
                            .TypeConstraint<int32>("T")
                            .HostMemory("input")
                            .HostMemory("output"),
                        RankOp);

REGISTER_KERNEL_BUILDER(Name("Rank")
                            .Device(DEVICE_GPU)
                            .TypeConstraint<bool>("T")
                            .HostMemory("input")
                            .HostMemory("output"),
                        RankOp);
#endif

class SizeOp : public OpKernel {
 public:
  explicit SizeOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext* ctx) override {
    const Tensor& inp = ctx->input(0);
    const int64 size = inp.NumElements();
    Tensor* out = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, TensorShape({}), &out));
    OP_REQUIRES(ctx, FastBoundsCheck(size, std::numeric_limits<int32>::max()),
                errors::InvalidArgument("Size does not work for tensors > "
                                        "int32 max."));
    // TODO(josh11b): switch output to int64?  (b/28119922)
    out->scalar<int32>()() = static_cast<int32>(size);
  }

  bool IsExpensive() override { return false; }
};
REGISTER_KERNEL_BUILDER(Name("Size").Device(DEVICE_CPU).HostMemory("output"),
                        SizeOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                        \
  REGISTER_KERNEL_BUILDER(Name("Size")                   \
                              .Device(DEVICE_GPU)        \
                              .TypeConstraint<type>("T") \
                              .HostMemory("output"),     \
                          SizeOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

// A special GPU kernel for int32.
// TODO(b/25387198): Also enable int32 in device memory. This kernel
// registration requires all int32 inputs and outputs to be in host memory.
REGISTER_KERNEL_BUILDER(Name("Size")
                            .Device(DEVICE_GPU)
                            .TypeConstraint<int32>("T")
                            .HostMemory("input")
                            .HostMemory("output"),
                        SizeOp);
#endif

class ExpandDimsOp : public OpKernel {
 public:
  explicit ExpandDimsOp(OpKernelConstruction* ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext* ctx) override {
    int dim = ctx->input(1).flat<int>()(0);
    OP_REQUIRES(
        ctx, (dim >= -1 - ctx->input(0).dims() && dim <= ctx->input(0).dims()),
        errors::InvalidArgument("Tried to expand dim index ", dim,
                                " for tensor with ", ctx->input(0).dims(),
                                " dimensions."));

    auto existing_dims = ctx->input(0).shape().dim_sizes();
    // Safe - # elements in tensor dims bounded.
    const int existing_dims_size = static_cast<int>(existing_dims.size());
    std::vector<int64> new_shape(existing_dims_size);
    for (size_t i = 0; i < new_shape.size(); ++i) {
      new_shape[i] = existing_dims[i];
    }

    // We emulate numpy's interpretation of the dim axis when
    // -input.dims() >= dim <= input.dims().
    if (dim < 0) {
      dim += existing_dims.size() + 1;
    }

    // Clamp to the end if needed.
    dim = std::min<int32>(dim, existing_dims_size);
    new_shape.emplace(new_shape.begin() + dim, 1);
    const TensorShape output_shape(new_shape);

    Tensor* output = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, {0}, &output));
    if (!output->CopyFrom(ctx->input(0), output_shape)) {
      // This should never happen, since the sizes of the input and output
      // should always be the same (we only expand the dimension with 1).
      ctx->SetStatus(
          errors::Internal("Could not expand dimension with input shape ",
                           ctx->input(0).shape().DebugString(),
                           " and output shape ", output_shape.DebugString()));
    }
  }

  bool IsExpensive() override { return false; }
};
REGISTER_KERNEL_BUILDER(Name("ExpandDims").Device(DEVICE_CPU).HostMemory("dim"),
                        ExpandDimsOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                        \
  REGISTER_KERNEL_BUILDER(Name("ExpandDims")             \
                              .Device(DEVICE_GPU)        \
                              .TypeConstraint<type>("T") \
                              .HostMemory("dim"),        \
                          ExpandDimsOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

REGISTER_KERNEL_BUILDER(Name("ExpandDims")
                            .Device(DEVICE_GPU)
                            .TypeConstraint<int32>("T")
                            .HostMemory("input")
                            .HostMemory("dim")
                            .HostMemory("output"),
                        ExpandDimsOp);
#endif

class SqueezeOp : public OpKernel {
 public:
  explicit SqueezeOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    std::vector<int32> squeeze_dims;
    OP_REQUIRES_OK(ctx, ctx->GetAttr("squeeze_dims", &squeeze_dims));
    squeeze_dims_.insert(squeeze_dims.begin(), squeeze_dims.end());
  }

  void Compute(OpKernelContext* ctx) override {
    auto existing_dims = ctx->input(0).shape().dim_sizes();
    const int existing_dims_size = static_cast<int>(existing_dims.size());
    std::vector<int64> new_shape;

    std::unordered_set<int32> wrapped_squeeze_dims;
    wrapped_squeeze_dims.reserve(squeeze_dims_.size());
    // Validate squeeze dims against the input.
    for (int32 dim : squeeze_dims_) {
      OP_REQUIRES(
          ctx, (dim >= -ctx->input(0).dims() && dim < ctx->input(0).dims()),
          errors::InvalidArgument("Tried to squeeze dim index ", dim,
                                  " for tensor with ", ctx->input(0).dims(),
                                  " dimensions."));
      // If dim is < 0, we wrap around (-1 means the last element).
      if (dim < 0) {
        dim = existing_dims_size + dim;
      }

      wrapped_squeeze_dims.insert(dim);
    }

    for (int i = 0; i < existing_dims_size; ++i) {
      auto existing_dim = existing_dims[i];

      // If squeeze_set is non-empty, only squeeze those dimensions.
      if (!wrapped_squeeze_dims.empty()) {
        if (wrapped_squeeze_dims.count(i) > 0) {
          OP_REQUIRES(ctx, existing_dim == 1,
                      errors::InvalidArgument("Tried to explicitly squeeze "
                                              "dimension ",
                                              i, " but dimension was not 1: ",
                                              existing_dim));
        } else {
          // This dimension is not being squeezed.
          new_shape.push_back(existing_dim);
        }
      } else {
        // Copy over all non-1-length dimensions.
        if (existing_dim != 1) {
          new_shape.push_back(existing_dim);
        }
      }
    }

    const TensorShape output_shape(new_shape);
    Tensor* output = nullptr;
    OP_REQUIRES_OK(ctx, ctx->allocate_output(0, {0}, &output));
    if (!output->CopyFrom(ctx->input(0), output_shape)) {
      // This should never happen, since the sizes of the input and
      // output should always be the same.
      ctx->SetStatus(errors::Internal("Could not squeeze input with shape ",
                                      ctx->input(0).shape().DebugString(),
                                      " and output shape ",
                                      output_shape.DebugString()));
    }
  }

  bool IsExpensive() override { return false; }

 private:
  std::unordered_set<int32> squeeze_dims_;
};

REGISTER_KERNEL_BUILDER(Name("Squeeze").Device(DEVICE_CPU), SqueezeOp);

#if GOOGLE_CUDA
#define REGISTER_GPU_KERNEL(type)                                   \
  REGISTER_KERNEL_BUILDER(                                          \
      Name("Squeeze").Device(DEVICE_GPU).TypeConstraint<type>("T"), \
      SqueezeOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER_GPU_KERNEL);
#undef REGISTER_GPU_KERNEL

// A special GPU kernel for int32.
// TODO(b/25387198): Also enable int32 in device memory. This kernel
// registration requires all int32 inputs and outputs to be in host memory.
REGISTER_KERNEL_BUILDER(Name("Squeeze")
                            .Device(DEVICE_GPU)
                            .TypeConstraint<int32>("T")
                            .HostMemory("input")
                            .HostMemory("output"),
                        SqueezeOp);
#endif

}  // namespace tensorflow
<|endoftext|>


<commit_before>// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - 2>&1 -std=c++11 | FileCheck %s

int gi;

namespace lambdas {
// CHECK-LABEL: define void @_ZN7lambdas7LambdasEPc
void Lambdas(char *ptr) {
  auto L1 = [](void *const p __attribute__((pass_object_size(0)))) {
    return __builtin_object_size(p, 0);
  };

  int i = 0;
  auto L2 = [&i](void *const p __attribute__((pass_object_size(0)))) {
    return __builtin_object_size(p, 0) + i;
  };

  // CHECK: @llvm.objectsize
  gi = L1(ptr);
  // CHECK: @llvm.objectsize
  gi = L2(ptr);
}

// CHECK-DAG: define internal i64 @"_ZZN7lambdas7LambdasEPcENK3$_0clEPvU17pass_object_size0"
// CHECK-NOT: call i64 @llvm.objectsize
// CHECK-DAG: define internal i64 @"_ZZN7lambdas7LambdasEPcENK3$_1clEPvU17pass_object_size0"
// CHECK-NOT: call i64 @llvm.objectsize
}

// This is here instead of in Sema/ because we need to check to make sure the
// proper function is called. If it's not, we'll end up with assertion errors.
namespace addrof {
void OvlFoo(void *const __attribute__((pass_object_size(0)))) {}
void OvlFoo(int *const) {}

// CHECK: define void @_ZN6addrof4TestEv
void Test() {
  // Treating parens-only calls as though they were direct is consistent with
  // how we handle other implicitly unaddressable functions (e.g. builtins).
  // CHECK: call void @_ZN6addrof6OvlFooEPvU17pass_object_size0
  (OvlFoo)(nullptr);

  // CHECK: call void @_ZN6addrof6OvlFooEPi
  (&OvlFoo)(nullptr);
}
}
<commit_msg>Add a test to ensure that pass_object_size is handled properly by a delegate constructor.<commit_after>// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - 2>&1 -std=c++11 | FileCheck %s

int gi;

namespace lambdas {
// CHECK-LABEL: define void @_ZN7lambdas7LambdasEPc
void Lambdas(char *ptr) {
  auto L1 = [](void *const p __attribute__((pass_object_size(0)))) {
    return __builtin_object_size(p, 0);
  };

  int i = 0;
  auto L2 = [&i](void *const p __attribute__((pass_object_size(0)))) {
    return __builtin_object_size(p, 0) + i;
  };

  // CHECK: @llvm.objectsize
  gi = L1(ptr);
  // CHECK: @llvm.objectsize
  gi = L2(ptr);
}

// CHECK-DAG: define internal i64 @"_ZZN7lambdas7LambdasEPcENK3$_0clEPvU17pass_object_size0"
// CHECK-NOT: call i64 @llvm.objectsize
// CHECK-DAG: define internal i64 @"_ZZN7lambdas7LambdasEPcENK3$_1clEPvU17pass_object_size0"
// CHECK-NOT: call i64 @llvm.objectsize
}

// This is here instead of in Sema/ because we need to check to make sure the
// proper function is called. If it's not, we'll end up with assertion errors.
namespace addrof {
void OvlFoo(void *const __attribute__((pass_object_size(0)))) {}
void OvlFoo(int *const) {}

// CHECK: define void @_ZN6addrof4TestEv
void Test() {
  // Treating parens-only calls as though they were direct is consistent with
  // how we handle other implicitly unaddressable functions (e.g. builtins).
  // CHECK: call void @_ZN6addrof6OvlFooEPvU17pass_object_size0
  (OvlFoo)(nullptr);

  // CHECK: call void @_ZN6addrof6OvlFooEPi
  (&OvlFoo)(nullptr);
}
}

namespace delegate {
  struct A {
    A(void *const p __attribute__((pass_object_size(0))));
  };
  A::A(void *const p __attribute__((pass_object_size(0)))) {}
  // Ensure that we forward the size through a delegating constructor call.
  // CHECK: define void @_ZN8delegate1AC1EPvU17pass_object_size0({{[^,]*}}, i8*{{[^,]*}}, i64{{[^,]*}})
  // CHECK: call void @_ZN8delegate1AC2EPvU17pass_object_size0({{[^,]*}}, i8*{{[^,]*}}, i64{{[^,]*}})
}
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include <fstream>
#include "../src/core/Timer.cpp"
#include "../src/scene/SceneManager.h"
#include "../src/scene/Ionosphere.h"
#include "../src/tracer/Ray.h"
#include "../src/math/Vector3d.h"
#include "../src/math/Line3d.h"
#include "../src/core/Config.h"
#include "../src/core/Application.h"

namespace {

	using namespace raytracer::core;
	using namespace raytracer::scene;
	using namespace raytracer::math;

	class SceneManagerPerformanceTest : public ::testing::Test {

		protected:
			void SetUp() {
				conf = Config("config/scenario_test.json");
				Application::getInstance().setCelestialConfig(conf);
				appConf = Config("config/config.json");
				Application::getInstance().setApplicationConfig(conf);

				R = 3390e3;
			}

			double R;
			Config conf, appConf;
	};

	TEST_F(SceneManagerPerformanceTest, OneMillionMeshes) {

		SceneManager scm = SceneManager();

		// init
		int numSceneObjectsCreated = 0;
		int start = 1000;
		int dh = 20;
		int end = 101e3;
		double angularStepSize = Constants::PI/200.0;
		Ray r = Ray();
		r.frequency = 4e6;
		r.o = Vector3d(0, R, 0);
		Line3d rayLine = Line3d(r.o, Vector3d(R + 100e3, R + 100e3, 0));
		ofstream data;
		data.open("testresults1M.txt");

		// create scene
		for (double theta = -Constants::PI/2 + angularStepSize; theta < Constants::PI/2; theta += angularStepSize) {
			for (int h = start; h < end; h += dh) {

				Vector3d N = Vector3d(cos(theta), sin(theta), 1).norm();
				Plane3d mesh = Plane3d(N, Vector3d((R+h)*N.x, (R+h)*N.y, (R+h)*N.z));
				mesh.size = angularStepSize * R;
				Ionosphere* io = new Ionosphere(mesh);
				io->layerHeight = dh;

				numSceneObjectsCreated++;
				scm.addToScene(io);
			}
		}

		scm.sortScene();

		// repeat test multiple times
		double tAvg = 0;
		int testRuns = 25;
		double runningTimes[testRuns];
		double variance = 0;
		for (int i = 0; i < testRuns; i++) {

			// perform intersection test
			Timer tmr;

			scm.intersect(r, rayLine);

			double t = tmr.elapsed() * 1000.;
			runningTimes[i] = t;
			tAvg += t/((double)testRuns);
			tmr.reset();
		}

		for (int j = 0; j < testRuns; j++) {

			variance += abs(runningTimes[j] - tAvg) / ((double)testRuns);
		}

		data << "Average elapsed time: " << ::testing::PrintToString(tAvg) << "ms" << endl;
		data << "Standard deviation: su = " << ::testing::PrintToString(sqrt(variance)) << "ms" << endl;
		data << "Objects created: " << ::testing::PrintToString(numSceneObjectsCreated) << "" << endl	;
		data << "Intersections per ms: " << ::testing::PrintToString(numSceneObjectsCreated/tAvg) << "" << endl;
	}
}
<commit_msg>SceneManagerPerformanceTest no longer required<commit_after><|endoftext|>